diff options
author | Luo Jinghua <sunmoon1997@gmail.com> | 2009-09-15 23:55:49 +0800 |
---|---|---|
committer | Luo Jinghua <sunmoon1997@gmail.com> | 2009-09-15 23:55:49 +0800 |
commit | 1a1a80bd23418de54976032b2a54de7c9670946a (patch) | |
tree | 5b90c51313d1f5843d522c01f0a6c701505a4304 | |
parent | 0f393eff94c3c7a32502eccd5e210612703844d9 (diff) |
totem, po: add a custom channel list
-rw-r--r-- | po/zh_CN.po | 87 | ||||
-rw-r--r-- | totem/plugin/Makefile.am | 4 | ||||
-rw-r--r-- | totem/plugin/channels.pls | 234 | ||||
-rw-r--r-- | totem/plugin/sopcast.py | 288 | ||||
-rw-r--r-- | totem/plugin/sopcast.ui | 189 |
5 files changed, 783 insertions, 19 deletions
diff --git a/po/zh_CN.po b/po/zh_CN.po index a7a7827..69e1672 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -5,52 +5,104 @@ # msgid "" msgstr "" -"Project-Id-Version: totem-pps 0.0.17\n" +"Project-Id-Version: totem-sopcast 0.0.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-13 11:17+0800\n" -"PO-Revision-Date: 2009-09-06 12:21+0800\n" +"POT-Creation-Date: 2009-09-15 23:44+0800\n" +"PO-Revision-Date: 2009-09-15 23:45+0800\n" "Last-Translator: Luo Jinghua <sunmoon1997@gmail.com>\n" "Language-Team: Luo Jinghua <sunmoon1997@gmail.com>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../totem/plugin/sopcast.py:210 ../totem/plugin/sopcast.py:401 +#: ../totem/plugin/sopcast.py:215 ../totem/plugin/sopcast.py:691 msgid "Sopcast" -msgstr "" +msgstr "Sopcast" -#: ../totem/plugin/sopcast.py:288 +#: ../totem/plugin/sopcast.py:377 msgid "Downloading channel list..." msgstr "加载频道列表中..." -#: ../totem/plugin/sopcast.py:368 +#: ../totem/plugin/sopcast.py:467 ../totem/plugin/sopcast.py:600 msgid "Name" msgstr "名称" -#: ../totem/plugin/sopcast.py:372 +#: ../totem/plugin/sopcast.py:471 msgid "Number" msgstr "数量" -#: ../totem/plugin/sopcast.py:401 +#: ../totem/plugin/sopcast.py:604 +msgid "Location" +msgstr "位置" + +#: ../totem/plugin/sopcast.py:691 #, python-format msgid "" "Totem cannot play this type of media (%s) because you do not have the " "appropriate plugins to handle it." msgstr "Totem 无法播放此介质类型(%s),原因是您没有可处理该类型的适当插件。" -#: ../totem/plugin/sopcast.py:402 +#: ../totem/plugin/sopcast.py:692 msgid "" "Please install the necessary plugins and restart Totem to be able to play " "this media." msgstr "请按装必需的插件,然后重新启动 Totem,这样才能播放此介质。" -#: ../totem/plugin/sopcast.py:404 +#: ../totem/plugin/sopcast.py:694 msgid "More information about media plugins" msgstr "更多的关于媒体插件的信息" #: ../totem/plugin/sopcast.ui.h:1 -msgid "Channels" -msgstr "频道" +msgid "Add a new station to the list" +msgstr "新增一个电视" + +#: ../totem/plugin/sopcast.ui.h:2 +msgid "Add a station to station list" +msgstr "添加一个电视节目到列表中" + +#: ../totem/plugin/sopcast.ui.h:3 +msgid "Add the station to list" +msgstr "添加到电视列表(_A)" + +#: ../totem/plugin/sopcast.ui.h:4 +msgid "Channels(Personal)" +msgstr "频道(个人的)" + +#: ../totem/plugin/sopcast.ui.h:5 +msgid "Channels(Sopcast)" +msgstr "频道(Sopcast)" + +#: ../totem/plugin/sopcast.ui.h:6 +msgid "Copy the location to the clipboard" +msgstr "复制位置到剪切板" + +#: ../totem/plugin/sopcast.ui.h:7 +msgid "Location:" +msgstr "位置:" + +#: ../totem/plugin/sopcast.ui.h:8 +msgid "Name:" +msgstr "名称:" + +#: ../totem/plugin/sopcast.ui.h:9 +msgid "Remove the station from list" +msgstr "删除电视(_R)" + +#: ../totem/plugin/sopcast.ui.h:10 +msgid "_Add the station" +msgstr "添加到电视列表(_A)" + +#: ../totem/plugin/sopcast.ui.h:11 +msgid "_Copy Location" +msgstr "复制位置(_C)" + +#: ../totem/plugin/sopcast.ui.h:12 +msgid "_New station" +msgstr "新增电视(_N)" + +#: ../totem/plugin/sopcast.ui.h:13 +msgid "_Remove the station" +msgstr "删除电视(_R)" #: ../totem/plugin/sopcast-config.ui.h:1 msgid "<b>Sopcast</b>" @@ -84,3 +136,12 @@ msgstr "一个可以浏览 Sopcast 频道的插件" #: ../totem/plugin/sopcast.totem-plugin.in.h:2 msgid "Sopcast browser" msgstr "Sopcast 浏览器" + +#~ msgid "Stations(Custom)" +#~ msgstr "电视(自定的)" + +#~ msgid "_Add to Station list" +#~ msgstr "添加到电视列表中(_A)" + +#~ msgid "_Remove from Station list" +#~ msgstr "从电视列表中删除(_R)" diff --git a/totem/plugin/Makefile.am b/totem/plugin/Makefile.am index 3997d92..89971bf 100644 --- a/totem/plugin/Makefile.am +++ b/totem/plugin/Makefile.am @@ -14,9 +14,9 @@ plugin_in_files = sopcast.totem-plugin.in %.totem-plugin: %.totem-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache plugin_DATA = $(plugin_in_files:.totem-plugin.in=.totem-plugin) sopcast_translation.py -ui_DATA = sopcast.ui sopcast-config.ui +ui_DATA = sopcast.ui sopcast-config.ui channels.pls -EXTRA_DIST = $(plugin_in_files) $(ui_DATA) sopcast.py sopcast_translation.py.in channelguide.py +EXTRA_DIST = $(plugin_in_files) $(ui_DATA) sopcast.py sopcast_translation.py.in channelguide.py channels.pls CLEANFILES = $(plugin_DATA) sopcast_translation.py DISTCLEANFILES = $(plugin_DATA) sopcast_translation.py diff --git a/totem/plugin/channels.pls b/totem/plugin/channels.pls new file mode 100644 index 0000000..9922745 --- /dev/null +++ b/totem/plugin/channels.pls @@ -0,0 +1,234 @@ +[playlist] +NumberOfEntries=116 +File1=mms://live.cctv.com/cctv_live1 +Title1=CCTV 1 +File2=mms://live.cctv.com/live12 +Title2=CCTV 2 +File3=mms://live.cctv.com/live13 +Title3=CCTV 3 +File4=mms://live.cctv.com/cctv_live4 +Title4=CCTV 4 +File5=mms://live.cctv.com/live15 +Title5=CCTV 5 +File6=mms://live.cctv.com/live16 +Title6=CCTV 6 +File7=mms://live.cctv.com/live17 +Title7=CCTV 7 +File8=mms://live.cctv.com/cctv_live9 +Title8=CCTV 9 +File9=mms://live.cctv.com/live20 +Title9=CCTV 10 +File10=mms://live.cctv.com/live21 +Title10=CCTV 11 +File11=mms://live.cctv.com/live22 +Title11=CCTV 12 +File12=mms://live.cctv.com/livenews +Title12=CCTV 新闻 +File13=mms://live.cctv.com/livekids +Title13=CCTV 少儿 +File14=mms://live.cctv.com/livemusic +Title14=CCTV 音乐 +File15=mms://gouwu.live.cctv.com/livegouwu?cccode=cc1289 +Title15=CCTV 购物 +File16=mms://live.cctv.com/livefengyun +Title16=CCTV 风云足球 +File17=mms://211.167.102.66/ch-04 +Title17=Bloomberg +File18=mms://211.167.102.66/ch-11 +Title18=探索频道 +File19=mms://211.167.102.66/ch-19 +Title19=国家地理 +File20=mms://61.139.37.135/blsz +Title20=法国时尚 +File21=mms://211.167.102.66/ch-14 +Title21=ESPN体育 +File22=mms://211.167.102.67/ch-17 +Title22=卫视体育 +File23=mms://61.139.37.135/starmovies +Title23=好莱坞电影 +File24=mms://61.139.37.135/aoya +Title24=Aoya电影 +File25=mms://211.156.249.76/yl100tv001 +Title25=高清影视 +File26=mms://195.244.137.207:81 +Title26=1 Music +File27=mms://211.167.102.66/ch-03 +Title27=Channal [V] +File28=mms://morrich.gekimedia.net/MainStream500 +Title28=SonyMusic +File29=mms://living.chinabroadcast.cn/hqzx +Title29=环球资讯 +File30=mms://211.167.102.66/ch-01 +Title30=凤凰资讯 +File31=mms://211.167.102.66/ch-02 +Title31=凤凰卫视 +File32=mms://61.139.37.135/xgxz +Title32=香港新知 +File33=mms://211.167.102.66/ch-20 +Title33=AXN香港 +File34=mms://61.139.37.135/tvb8 +Title34=TVB电影 +File35=mms://211.167.102.66/ch-07 +Title35=TVB星河 +File36=mms://211.167.102.66/ch-08 +Title36=TVBS +File37=mms://211.167.102.66/ch-05 +Title37=TVB8 +File38=mms://211.167.102.66/ch-15 +Title38=大爱 +File39=mms://211.167.102.66/ch-06 +Title39=华娱卫视 +File40=mms://211.167.102.66/ch-12 +Title40=东风卫视 +File41=mms://211.167.102.66/ch-13 +Title41=东森综合 +File42=mms://211.167.102.66/ch-18 +Title42=东森电影 +File43=mms://211.167.102.66/ch-16 +Title43=中天综合 +File44=mms://211.157.10.21/suntv +Title44=阳光卫视 +File45=mms://61.139.37.135/star +Title45=星空卫视 +File46=mms://61.139.37.135/dfws +Title46=上海东方卫视 +File47=mms://211.167.102.66/ch-10 +Title47=上海体育 +File48=mms://mediasrv2.iptv.xmg.com.cn/tvhaixia +Title48=厦门卫视 +File49=mms://mediasrv2.iptv.xmg.com.cn/tvxinwen +Title49=厦门新闻 +File50=mms://mediasrv2.iptv.xmg.com.cn/tvjishi +Title50=厦门纪实 +File51=mms://mediasrv2.iptv.xmg.com.cn/tvshenghuo +Title51=厦门生活 +File52=mms://mediasrv2.iptv.xmg.com.cn/tvyingshi +Title52=厦门影视 +File53=mms://61.175.162.21/ztv2 +Title53=浙江钱江在线 +File54=mms://61.175.162.21/ztv3 +Title54=浙江经视 +File55=mms://61.175.162.21/ztv4 +Title55=浙江教育科技 +File56=mms://61.175.162.21/ztv5 +Title56=浙江影视 +File57=mms://61.175.162.21/ztv8 +Title57=浙江少儿 +File58=mmsh://live.njbg.com.cn:88/NJTV01?MSWMExt=.asf +Title58=南京新闻综合 +File59=mmsh://live.njbg.com.cn:88/NJTV03?MSWMExt=.asf +Title59=南京娱乐 +File60=mmsh://live.njbg.com.cn:88/NJTV04?MSWMExt=.asf +Title60=南京生活 +File61=mmsh://live.njbg.com.cn:88/NJTV05?MSWMExt=.asf +Title61=南京科教 +File62=mmsh://live.njbg.com.cn:88/NJTV06?MSWMExt=.asf +Title62=南京信息 +File63=mmsh://live.njbg.com.cn:88/NJTV18?MSWMExt=.asf +Title63=南京十八 +File64=mms://218.3.205.21/xwzhpd +Title64=徐州新闻综合 +File65=mms://218.3.205.21/jjshpd +Title65=徐州经济生活 +File66=mms://218.3.205.21/wyyspd +Title66=徐州文艺影视 +File67=mms://218.3.205.21/shzfpd +Title67=徐州公共 +File68=mms://vod1.cztv.tv/cztv1 +Title68=常州新闻 +File69=mms://vod1.cztv.tv/cztv2 +Title69=常州都市 +File70=mms://vod1.cztv.tv/cztv3 +Title70=常州影视 +File71=mms://vod1.cztv.tv/cztv4 +Title71=常州公共 +File72=mmsh://61.159.229.233/yntv-1?MSWMExt=.asf +Title72=云南卫视 +File73=mmsh://61.159.229.233/yntv-2?MSWMExt=.asf +Title73=云南都市 +File74=mmsh://61.159.229.233/yntv-3?MSWMExt=.asf +Title74=云南娱乐 +File75=mmsh://61.159.229.233/yntv-4?MSWMExt=.asf +Title75=云南生活资讯 +File76=mmsh://61.159.229.233/yntv-6?MSWMExt=.asf +Title76=云南公共 +File77=mms://61.139.37.135/HUNA +Title77=湖南卫视 +File78=mms://218.6.174.207/sctv1 +Title78=四川卫视 +File79=mms://218.6.174.207/sctv2 +Title79=四川文化旅游 +File80=mms://218.6.174.207/sctv3 +Title80=四川经济 +File81=mms://218.6.174.207/sctv4 +Title81=四川4 +File82=mms://218.6.174.207/sctv5 +Title82=四川影视文艺 +File83=mms://218.6.174.207/sctv6 +Title83=四川6 +File84=mms://218.6.174.207/sctv7 +Title84=四川妇女儿童 +File85=mms://218.6.174.207/sctv9 +Title85=四川公共 +File86=mms://vod.chengdutv.com/news +Title86=成都新闻综合 +File87=mms://vod.chengdutv.com/economy +Title87=成都经济资讯 +File88=mms://vod.chengdutv.com/life +Title88=成都都市生活 +File89=mms://vod.chengdutv.com/film +Title89=成都影视文艺 +File90=mms://vod.chengdutv.com/common +Title90=成都公共 +File91=mms://vod.chengdutv.com/child +Title91=成都少儿 +File92=mms://live.cbg.cn/cqws +Title92=重庆卫视 +File93=mms://live.cbg.cn/cqds +Title93=重庆都市 +File94=mms://live.cbg.cn/cqss +Title94=重庆时尚 +File95=mms://live.cbg.cn/cqgj +Title95=重庆国际 +File96=mms://live.cbg.cn/cqkj +Title96=重庆科教 +File97=mms://live.cbg.cn/gzcp +Title97=重庆公众彩票 +File98=mms://live.cbg.cn/qmpd +Title98=重庆汽摩 +File99=mms://live.cbg.cn/mlsz +Title99=重庆魅力时装 +File100=mms://live2.ncnews.com.cn/sjb +Title100=南昌电视台4 +File101=mms://202.96.114.251/lstv +Title101=丽水新闻综合 +File102=mms://202.96.114.251/lstv2 +Title102=丽水经济生活 +File103=mms://61.136.113.41/nytv_1 +Title103=南阳1 +File104=mms://61.136.113.41/nytv_2 +Title104=南阳2 +File105=mms://219.144.186.195/station1 +Title105=西安1 +File106=mms://220.171.12.184/btzx +Title106=新疆兵团-1 +File107=mms://202.107.35.51/live1 +Title107=辽宁卫视 +File108=mms://202.107.35.51/live2 +Title108=辽宁都市 +File109=mms://202.107.35.51/live3 +Title109=辽宁影视娱乐 +File110=mms://202.107.35.51/live4 +Title110=辽宁体育 +File111=mms://202.107.35.51/live5 +Title111=辽宁青少 +File112=mms://202.107.35.51/live6 +Title112=辽宁生活 +File113=mms://202.107.35.51/live7 +Title113=辽宁游戏竞技 +File114=mms://221.0.171.202/qtv +Title114=青岛综合 +File115=mms://video.chinactv.com/ctv +Title115=长春综合 +File116=mms://221.212.177.20/vod +Title116=黑龙江卫视 diff --git a/totem/plugin/sopcast.py b/totem/plugin/sopcast.py index 53f2a03..21e3e03 100644 --- a/totem/plugin/sopcast.py +++ b/totem/plugin/sopcast.py @@ -9,6 +9,7 @@ import time import re import os import random +import ConfigParser import gettext from xml.dom import minidom @@ -45,7 +46,8 @@ def unescape_xml (data): gconf_key = '/apps/totem/plugins/sctream' sc_cache_dir = os.path.expanduser ('~/.local/share/totem/plugin/sopcast') - +sc_system_playlist = os.path.join (os.path.dirname (__file__), 'channels.pls') +sc_playlist = os.path.join (sc_cache_dir, 'channels.pls') sc_xmls_dir = os.path.join (sc_cache_dir, "xmls") sc_images_dir = os.path.join (sc_cache_dir, "images") @@ -124,6 +126,8 @@ class Sopcast (totem.Plugin): self.channels += [ 'http://channel.sopcast.cn/gchlxml' ] self.channels += [ 'http://people.freedesktop.org/~jinghua/sopcast/gchlxml' ] self.channels_index = 0 + self.source_id = 0 + self.playlist = [] def update_translation (self, builder): for obj in builder.get_objects (): @@ -199,10 +203,12 @@ class Sopcast (totem.Plugin): self.notebook = self.builder.get_object ("sc_notebook") self.notebook.connect ("switch-page", self.on_notebook_page_changed) - self.notebook_pages = ["channels"] + self.notebook_pages = ["channels", 'playlist'] self.current_treeview_name = "channels" self.load_config () + self.setup_popup_menu () self.setup_channels () + self.setup_playlist () self.setup_config_dialog () self.vbox = self.builder.get_object ("sc_vbox") @@ -249,6 +255,90 @@ class Sopcast (totem.Plugin): time.sleep (0.001) return True + def on_add_to_station_list (self, treeview): + treeview_name = self.current_treeview_name + treeview = self.treeview[treeview_name] + selection = treeview.get_selection () + model = treeview.get_model () + model, rows = selection.get_selected_rows () + + for row in rows: + iter = model.get_iter (row) + mrl = model.get_value (iter, 2) + print mrl + + def on_remove_from_station_list (self, treeview): + treeview_name = self.current_treeview_name + assert treeview_name == 'playlist' + + treeview = self.treeview[treeview_name] + selection = treeview.get_selection () + model = treeview.get_model () + model, rows = selection.get_selected_rows () + + for row in rows: + self.remove_from_playlist (row[0]) + + def on_copy_location (self, action): + treeview_name = self.current_treeview_name + treeview = self.treeview[treeview_name] + selection = treeview.get_selection () + model = treeview.get_model () + model, rows = selection.get_selected_rows () + iter = model.get_iter (rows[0]) + if treeview_name == 'channels': + mrl = model.get_value (iter, 2) + else: + mrl = model.get_value (iter, 1) + + clip = gtk.Clipboard () + clip.set_text (mrl) + clip = gtk.Clipboard (display = gtk.gdk.display_get_default(), + selection = "PRIMARY") + clip.set_text (mrl) + + def on_add_station (self, action): + treeview_name = self.current_treeview_name + dialog = self.builder.get_object ('sopcast_add_station_dialog') + dialog.run () + + def on_add_station_dialog_delete (self, dialog, event): + dialog.hide () + return True + + def on_add_station_dialog_close (self, dialog): + dialog.hide () + + def on_add_station_dialog_response (self, dialog, response_id): + dialog.hide () + if response_id == gtk.RESPONSE_DELETE_EVENT: + return + elif response_id == 1: + return + + name = self.builder.get_object ('sopcast_add_station_name_entry').get_text ().strip () + location = self.builder.get_object ('sopcast_add_station_location_entry').get_text ().strip () + if not name or not location: + return + self.add_to_playlist (name, location) + + def setup_popup_menu (self): + self.ui_manager = self.builder.get_object ('sopcast-ui-manager') + action_group = self.ui_manager.get_action_groups () [0] + action = action_group.get_action ("add-to-station-list") + action.connect ('activate', self.on_add_to_station_list) + action = action_group.get_action ("remove-from-station-list") + action.connect ('activate', self.on_remove_from_station_list) + action = action_group.get_action ("copy-location") + action.connect ('activate', self.on_copy_location) + action = action_group.get_action ("add-station") + action.connect ('activate', self.on_add_station) + + dialog = self.builder.get_object ('sopcast_add_station_dialog') + dialog.connect ("response", self.on_add_station_dialog_response) + dialog.connect ("close", self.on_add_station_dialog_close) + dialog.connect ("delete-event", self.on_add_station_dialog_delete) + def on_channels_row_activated (self, treeview, path, view_column, data=None): model, rows = treeview.get_selection ().get_selected_rows () row = rows[0] @@ -393,6 +483,8 @@ class Sopcast (totem.Plugin): treeview.set_model (self.liststore[treeview_name]) treeview.connect("row_activated", self.on_channels_row_activated) + treeview.connect ("popup-menu", self.on_treeview_popup_menu) + treeview.connect ("button-press-event", self.on_treeview_button_pressed) self.channels_count = 0 self.channels_downloading = False @@ -402,6 +494,198 @@ class Sopcast (totem.Plugin): else: self.download_channels () + def load_playlist (self, path = sc_playlist): + parser = ConfigParser.ConfigParser () + if not parser.read ([path]): + return [] + if not parser.has_section ('playlist'): + return [] + result = {} + for item in parser.items ('playlist'): + key = item[0] + if key[0:4] == 'file': + index = str(key[4:]) + key = 'file' + elif key[0:5] == 'title': + index = str(key[5:]) + key = 'title' + else: + continue + if index not in result.keys (): + result[index] = {} + result[index][key] = item[1] + #print item, key, index, result[index] + + keys = result.keys () + keys.sort () + playlist = [] + for i in range (len (keys)): + title = result[keys[i]]['title'] + url = result[keys[i]]['file'] + playlist.append ((title, url)) + + return playlist + + def save_playlist (self, playlist): + if not playlist: + return False + parser = ConfigParser.RawConfigParser () + parser.add_section ('playlist') + parser.set ('playlist', 'NumberOfEntries', str (len (playlist))) + for i in range (len (playlist)): + parser.set ('playlist', 'File' + str (i + 1), playlist[i][1]) + parser.set ('playlist', 'Title' + str (i + 1), playlist[i][0]) + fp = None + try: + fp = file (sc_playlist, 'wb') + except: + return False + parser.write (fp) + fp.close () + return True + + def show_playlist (self): + treeview_name = 'playlist' + treeview = self.liststore[treeview_name] + self.clear_pages (treeview_name) + + for item in self.playlist: + iter = treeview.append (None) + treeview.set (iter, + 0, item[0], + 1, item[1]) + + def add_to_playlist (self, title, mrl): + treeview_name = 'playlist' + treeview = self.liststore[treeview_name] + if (title, mrl) in self.playlist: + return + + self.playlist.append ((title, mrl)) + self.save_playlist (self.playlist) + + iter = treeview.append (None) + treeview.set (iter, + 0, title, + 1, mrl) + + def remove_from_playlist (self, row): + treeview_name = 'playlist' + treeview = self.liststore[treeview_name] + + del self.playlist[row] + self.save_playlist (self.playlist) + + iter = treeview.get_iter (row) + treeview.remove (iter) + + def on_playlist_row_activated (self, treeview, path, view_column, data=None): + model, rows = treeview.get_selection ().get_selected_rows () + row = rows[0] + + iter = model.get_iter (row) + title = model.get_value (iter, 0) + mrl = model.get_value (iter, 1) + + if hasattr(self.totem, "add_to_playlist_and_play"): + self.totem.add_to_playlist_and_play (mrl, title, False) + else: + self.totem.action_remote (totem.REMOTE_COMMAND_REPLACE, mrl) + + def setup_playlist (self): + treeview_name = 'playlist' + treeview = self.builder.get_object ("sc_treeview_" + treeview_name) + renderer = gtk.CellRendererText () + renderer.set_property("xalign", 0.0) + + column = gtk.TreeViewColumn(_("Name"), renderer, text = 0) + column.set_clickable(True) + treeview.append_column(column) + + column = gtk.TreeViewColumn(_("Location"), renderer, text = 1) + treeview.append_column(column) + + self.vadjust[treeview_name] = treeview.get_vadjustment () + #self.vadjust[treeview_name].connect ("value-changed", self.on_playlist_value_changed) + vscroll = self.builder.get_object ("sc_scrolled_window_" + treeview_name).get_vscrollbar () + #vscroll.connect ("button-press-event", self.on_playlist_button_press_event) + #vscroll.connect ("button-release-event", self.on_playlist_button_release_event) + + self.liststore[treeview_name] = self.builder.get_object ("sc_liststore_" + treeview_name) + self.treeview[treeview_name] = treeview + treeview.set_model (self.liststore[treeview_name]) + + treeview.connect("row_activated", self.on_playlist_row_activated) + treeview.connect ("popup-menu", self.on_treeview_popup_menu) + treeview.connect ("button-press-event", self.on_treeview_button_pressed) + treeview.connect ("key-press-event", self.on_playlist_key_pressed) + + selection = treeview.get_selection () + selection.set_mode (gtk.SELECTION_MULTIPLE) + + try: + self.playlist = self.load_playlist () + if not self.playlist: + self.playlist = self.load_playlist (sc_system_playlist) + except Exception, e: + print 'Failed to load play list', e + self.playlist = [] + + self.show_playlist () + + def show_popup_menu (self, event = None): + treeview_name = self.current_treeview_name + treeview = self.treeview [treeview_name] + selection = treeview.get_selection () + + if event: + button = event.button + time = event.time + path = treeview.get_path_at_pos (int(event.x), int(event.y)) + if not path or not selection.path_is_selected (path[0]): + selection.unselect_all () + else: + time = gtk.get_current_event_time () + button = None + + count = selection.count_selected_rows () + if not count: + return False + + action_group = self.ui_manager.get_action_groups () [0] + action = action_group.get_action ("copy-location") + action.set_sensitive (count == 1) + + action = action_group.get_action ("add-to-station-list") + action.set_sensitive (treeview_name == 'channels') + + action = action_group.get_action ("remove-from-station-list") + action.set_sensitive (treeview_name == 'playlist') + + action = action_group.get_action ("add-station") + action.set_sensitive (treeview_name == 'playlist') + + menu = self.ui_manager.get_widget ("/sopcast-popup") + menu.select_first (False) + menu.popup (None, None, None, button, time) + + return True + + def on_treeview_popup_menu (self): + self.show_popup_menu () + + def on_treeview_button_pressed (self, widget, event, user_data = None): + if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: + return self.show_popup_menu (event) + return False + + def on_playlist_key_pressed (self, wiget, event, user_data = None): + if event.type == gtk.gdk.KEY_PRESS and \ + gtk.gdk.keyval_name (event.keyval) == 'Delete': + self.on_remove_from_station_list (self.treeview['playlist']) + return True + return False + def on_notebook_page_changed (self, notebook, notebook_page, page_num): self.current_treeview_name = self.notebook_pages[page_num] diff --git a/totem/plugin/sopcast.ui b/totem/plugin/sopcast.ui index 112f1cd..0c9f547 100644 --- a/totem/plugin/sopcast.ui +++ b/totem/plugin/sopcast.ui @@ -12,6 +12,14 @@ <column type="gchararray"/> </columns> </object> + <object class="GtkTreeStore" id="sc_liststore_playlist"> + <columns> + <!-- column-name Title --> + <column type="gchararray"/> + <!-- column-name MRL --> + <column type="gchararray"/> + </columns> + </object> <object class="GtkVBox" id="sc_vbox"> <property name="visible">True</property> <property name="orientation">vertical</property> @@ -93,9 +101,39 @@ <child type="tab"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> - <property name="label" translatable="yes">Channels</property> + <property name="label" translatable="yes">Channels(Sopcast)</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="sc_scrolled_window_playlist"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkTreeView" id="sc_treeview_playlist"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">sc_liststore_playlist</property> + <property name="headers_visible">False</property> + <property name="rules_hint">True</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Channels(Personal)</property> </object> <packing> + <property name="position">1</property> <property name="tab_fill">False</property> </packing> </child> @@ -114,5 +152,152 @@ </packing> </child> </object> - <object class="GtkUIManager" id="sc-list-ui-manager"/> + <object class="GtkDialog" id="sopcast_add_station_dialog"> + <property name="border_width">5</property> + <property name="title" translatable="yes">Add a station to station list</property> + <property name="type_hint">normal</property> + <property name="has_separator">False</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child> + <object class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <child> + <object class="GtkEntry" id="sopcast_add_station_name_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="sopcast_add_station_location_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="sopcast_add_station_name_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Name:</property> + </object> + </child> + <child> + <object class="GtkLabel" id="sopcast_add_station_location_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Location:</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="sopcast_add_station_ok_button"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="sopcast_add_station_cancel_button"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="0">sopcast_add_station_ok_button</action-widget> + <action-widget response="1">sopcast_add_station_cancel_button</action-widget> + </action-widgets> + </object> + <object class="GtkUIManager" id="sopcast-ui-manager"> + <child> + <object class="GtkActionGroup" id="sopcast-action-group"> + <child> + <object class="GtkAction" id="add-to-station-list"> + <property name="label" translatable="yes">_Add the station</property> + <property name="tooltip" translatable="yes">Add the station to list</property> + <property name="stock-id">gtk-add</property> + </object> + </child> + <child> + <object class="GtkAction" id="remove-from-station-list"> + <property name="label" translatable="yes">_Remove the station</property> + <property name="tooltip" translatable="yes">Remove the station from list</property> + <property name="stock-id">gtk-remove</property> + </object> + </child> + <child> + <object class="GtkAction" id="add-station"> + <property name="label" translatable="yes">_New station</property> + <property name="tooltip" translatable="yes">Add a new station to the list</property> + <property name="stock-id">gtk-add</property> + </object> + </child> + <child> + <object class="GtkAction" id="copy-location"> + <property name="label" translatable="yes">_Copy Location</property> + <property name="tooltip" translatable="yes">Copy the location to the clipboard</property> + <property name="stock-id">gtk-copy</property> + </object> + </child> + </object> + </child> + <ui> + <popup name="sopcast-popup"> + <menuitem name="add-to-station-list" action="add-to-station-list"/> + <menuitem name="remove-from-station-list" action="remove-from-station-list"/> + <menuitem name="add-station" action="add-station"/> + <menuitem name="copy-location" action="copy-location"/> + </popup> + </ui> + </object> </interface> |