mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-03-04 11:31:50 +01:00
crud support for timers
This commit is contained in:
1693
app/ui/control.glade
1693
app/ui/control.glade
File diff suppressed because it is too large
Load Diff
@@ -29,19 +29,21 @@
|
||||
""" Receiver control module via HTTP API. """
|
||||
import os
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from ftplib import all_errors
|
||||
from urllib.parse import quote
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
from .dialogs import get_builder, show_dialog, DialogType
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Page, Column
|
||||
from .dialogs import get_builder, show_dialog, DialogType, get_message
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Page, Column, KeyboardKey
|
||||
from ..commons import run_task, run_with_delay, log, run_idle
|
||||
from ..connections import HttpAPI, UtfFTP
|
||||
from ..eparser.ecommons import BqServiceType
|
||||
from ..settings import IS_DARWIN, PlayStreamsMode
|
||||
|
||||
|
||||
class EpgBox(Gtk.Box):
|
||||
class EpgTool(Gtk.Box):
|
||||
def __init__(self, app, http_api, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -49,21 +51,58 @@ class EpgBox(Gtk.Box):
|
||||
self._app = app
|
||||
self._app.connect("fav-changed", self.on_service_changed)
|
||||
|
||||
handlers = {"on_epg_press": self.on_epg_press}
|
||||
handlers = {"on_epg_press": self.on_epg_press,
|
||||
"on_timer_add": self.on_timer_add}
|
||||
|
||||
builder = get_builder(UI_RESOURCES_PATH + "control.glade", handlers, objects=("epg_frame", "epg_model"))
|
||||
self._view = builder.get_object("epg_view")
|
||||
self.pack_start(builder.get_object("epg_frame"), True, True, 0)
|
||||
self.show()
|
||||
|
||||
def on_epg_press(self, list_box, event):
|
||||
if event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS and len(list_box) > 0:
|
||||
row = list_box.get_selected_row()
|
||||
if row:
|
||||
self.set_timer_from_event_data(row.event_data)
|
||||
def on_timer_add(self, action=None, value=None):
|
||||
model, paths = self._view.get_selection().get_selected_rows()
|
||||
p_count = len(paths)
|
||||
|
||||
if p_count == 1:
|
||||
dialog = TimerTool.TimerDialog(TimerTool.TimerAction.EVENT, model[paths][-1])
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
pass
|
||||
dialog.destroy()
|
||||
elif p_count > 1:
|
||||
if show_dialog(DialogType.QUESTION, self._app.app_window,
|
||||
"Add timers for selected events?") != Gtk.ResponseType.OK:
|
||||
return True
|
||||
|
||||
self.add_timers_list((model[p][-1] for p in paths))
|
||||
else:
|
||||
self._app.show_error_message("No selected item!")
|
||||
|
||||
def add_timers_list(self, paths):
|
||||
ref_str = "timeraddbyeventid?sRef={}&eventid={}&justplay=0"
|
||||
refs = [ref_str.format(ev.get("e2eventservicereference", ""), ev.get("e2eventid", "")) for ev in paths]
|
||||
|
||||
gen = self.write_timers_list(refs)
|
||||
GLib.idle_add(lambda: next(gen, False))
|
||||
|
||||
def write_timers_list(self, refs):
|
||||
self._app.wait_dialog.show()
|
||||
tasks = list(refs)
|
||||
for ref in refs:
|
||||
self._http_api.send(HttpAPI.Request.TIMER, ref, lambda x: tasks.pop())
|
||||
yield True
|
||||
|
||||
while tasks:
|
||||
yield True
|
||||
|
||||
self._app.emit("change-page", Page.TIMERS.value)
|
||||
|
||||
def on_epg_press(self, view, event):
|
||||
if event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS and len(view.get_model()) > 0:
|
||||
self.on_timer_add()
|
||||
|
||||
def on_service_changed(self, app, ref):
|
||||
self._app._wait_dialog.show()
|
||||
self._app.wait_dialog.show()
|
||||
self._http_api.send(HttpAPI.Request.EPG, quote(ref), self.update_epg_data)
|
||||
|
||||
@run_idle
|
||||
@@ -71,7 +110,7 @@ class EpgBox(Gtk.Box):
|
||||
model = self._view.get_model()
|
||||
model.clear()
|
||||
list(map(model.append, (self.get_event_row(e) for e in epg.get("event_list", []))))
|
||||
self._app._wait_dialog.hide()
|
||||
self._app.wait_dialog.hide()
|
||||
|
||||
def get_event_row(self, event):
|
||||
title = event.get("e2eventtitle", "")
|
||||
@@ -85,25 +124,292 @@ class EpgBox(Gtk.Box):
|
||||
return title, time, desc, event
|
||||
|
||||
|
||||
class TimersBox(Gtk.Box):
|
||||
class TimerTool(Gtk.Box):
|
||||
TIME_STR = "%Y-%m-%d %H:%M"
|
||||
|
||||
ACTION = {"0": "Record", "1": "Zap"}
|
||||
|
||||
AFTER_EVENT = {"0": "Do Nothing",
|
||||
"1": "Standby",
|
||||
"2": "Shut down",
|
||||
"3": "Auto"}
|
||||
|
||||
class TimerAction(Enum):
|
||||
ADD = 0
|
||||
EVENT = 1
|
||||
CHANGE = 2
|
||||
|
||||
class TimerDialog(Gtk.Dialog):
|
||||
def __init__(self, action=None, timer_data=None, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self._action = action or TimerTool.TimerAction.ADD
|
||||
self._timer_data = timer_data or {}
|
||||
self._request = ""
|
||||
|
||||
handlers = {"on_timer_begins_set": self.on_timer_begins_set,
|
||||
"on_timer_ends_set": self.on_timer_ends_set}
|
||||
|
||||
builder = get_builder(UI_RESOURCES_PATH + "control.glade", handlers,
|
||||
objects=("timer_dialog_frame", "timer_ends_popover", "end_hour_adjustment",
|
||||
"min_end_adjustment", "timer_begins_popover", "begins_hour_adjustment",
|
||||
"min_begins_adjustment"))
|
||||
|
||||
self.set_title(get_message("Timer"))
|
||||
self.set_modal(True)
|
||||
self.set_skip_pager_hint(True)
|
||||
self.set_skip_taskbar_hint(True)
|
||||
self.set_resizable(False)
|
||||
|
||||
self._timer_name_entry = builder.get_object("timer_name_entry")
|
||||
self._timer_desc_entry = builder.get_object("timer_desc_entry")
|
||||
self._timer_service_entry = builder.get_object("timer_service_entry")
|
||||
self._timer_service_ref_entry = builder.get_object("timer_service_ref_entry")
|
||||
self._timer_event_id_entry = builder.get_object("timer_event_id_entry")
|
||||
self._timer_begins_entry = builder.get_object("timer_begins_entry")
|
||||
self._timer_ends_entry = builder.get_object("timer_ends_entry")
|
||||
self._timer_begins_calendar = builder.get_object("timer_begins_calendar")
|
||||
self._timer_begins_hr_button = builder.get_object("timer_begins_hr_button")
|
||||
self._timer_begins_min_button = builder.get_object("timer_begins_min_button")
|
||||
self._timer_ends_calendar = builder.get_object("timer_ends_calendar")
|
||||
self._timer_ends_hr_button = builder.get_object("timer_ends_hr_button")
|
||||
self._timer_ends_min_button = builder.get_object("timer_ends_min_button")
|
||||
self._timer_enabled_switch = builder.get_object("timer_enabled_switch")
|
||||
self._timer_action_combo_box = builder.get_object("timer_action_combo_box")
|
||||
self._timer_after_combo_box = builder.get_object("timer_after_combo_box")
|
||||
self._days_buttons = (builder.get_object("timer_mo_check_button"),
|
||||
builder.get_object("timer_tu_check_button"),
|
||||
builder.get_object("timer_we_check_button"),
|
||||
builder.get_object("timer_th_check_button"),
|
||||
builder.get_object("timer_fr_check_button"),
|
||||
builder.get_object("timer_sa_check_button"),
|
||||
builder.get_object("timer_su_check_button"))
|
||||
|
||||
self._timer_location_switch = builder.get_object("timer_location_switch")
|
||||
self._timer_location_entry = builder.get_object("timer_location_entry")
|
||||
self._timer_location_switch.bind_property("active", self._timer_location_entry, "sensitive")
|
||||
# Disable DnD for timer entries.
|
||||
self._timer_name_entry.drag_dest_unset()
|
||||
self._timer_desc_entry.drag_dest_unset()
|
||||
self._timer_service_entry.drag_dest_unset()
|
||||
|
||||
self.add_buttons(get_message("Cancel"), Gtk.ResponseType.CLOSE, get_message("Save"), Gtk.ResponseType.OK)
|
||||
self.get_content_area().pack_start(builder.get_object("timer_dialog_frame"), True, True, 5)
|
||||
|
||||
if self._action is TimerTool.TimerAction.ADD:
|
||||
self.set_timer_for_add()
|
||||
elif self._action is TimerTool.TimerAction.CHANGE:
|
||||
self.set_timer_for_edit()
|
||||
elif self._action is TimerTool.TimerAction.EVENT:
|
||||
self.set_timer_from_event_data()
|
||||
else:
|
||||
log("{} error: No action set for timer!".format(__class__.__name__))
|
||||
|
||||
@property
|
||||
def request(self):
|
||||
return self._request
|
||||
|
||||
def run(self):
|
||||
resp = super().run()
|
||||
if resp == Gtk.ResponseType.OK:
|
||||
self._request = self.get_request()
|
||||
return resp
|
||||
|
||||
def get_request(self):
|
||||
""" Constructs str representation of add/update request. """
|
||||
args = []
|
||||
t_data = self.get_timer_data()
|
||||
s_ref = quote(t_data.get("sRef", ""))
|
||||
|
||||
if self._action is TimerTool.TimerAction.EVENT:
|
||||
args.append("timeraddbyeventid?sRef={}".format(s_ref))
|
||||
args.append("eventid={}".format(t_data.get("eit", "0")))
|
||||
args.append("justplay={}".format(t_data.get("justplay", "")))
|
||||
args.append("tags={}".format(""))
|
||||
else:
|
||||
if self._action is TimerTool.TimerAction.ADD:
|
||||
args.append("timeradd?sRef={}".format(s_ref))
|
||||
args.append("deleteOldOnSave={}".format(0))
|
||||
elif self._action is TimerTool.TimerAction.CHANGE:
|
||||
args.append("timerchange?sRef={}".format(s_ref))
|
||||
args.append("channelOld={}".format(s_ref))
|
||||
args.append("beginOld={}".format(self._timer_data.get("e2timebegin", "0")))
|
||||
args.append("endOld={}".format(self._timer_data.get("e2timeend", "0")))
|
||||
args.append("deleteOldOnSave={}".format(1))
|
||||
|
||||
args.append("begin={}".format(t_data.get("begin", "")))
|
||||
args.append("end={}".format(t_data.get("end", "")))
|
||||
args.append("name={}".format(quote(t_data.get("name", ""))))
|
||||
args.append("description={}".format(quote(t_data.get("description", ""))))
|
||||
args.append("tags={}".format(""))
|
||||
args.append("eit={}".format("0"))
|
||||
args.append("disabled={}".format(t_data.get("disabled", "1")))
|
||||
args.append("justplay={}".format(t_data.get("justplay", "1")))
|
||||
args.append("afterevent={}".format(t_data.get("afterevent", "0")))
|
||||
args.append("repeated={}".format(TimerTool.get_repetition_flags(self._days_buttons)))
|
||||
|
||||
if self._timer_location_switch.get_active():
|
||||
args.append("dirname={}".format(self._timer_location_entry.get_text()))
|
||||
|
||||
return "&".join(args)
|
||||
|
||||
def on_timer_begins_set(self, action, value=None):
|
||||
self.set_begins_date(self.get_begins_date())
|
||||
|
||||
def on_timer_ends_set(self, action, value=None):
|
||||
self.set_ends_date(self.get_ends_date())
|
||||
|
||||
def get_begins_date(self):
|
||||
date = self._timer_begins_calendar.get_date()
|
||||
return datetime(year=date.year, month=date.month + 1, day=date.day,
|
||||
hour=int(self._timer_begins_hr_button.get_value()),
|
||||
minute=int(self._timer_begins_min_button.get_value()))
|
||||
|
||||
def set_begins_date(self, date):
|
||||
hour = date.hour
|
||||
minute = date.minute
|
||||
self._timer_begins_hr_button.set_value(hour)
|
||||
self._timer_begins_min_button.set_value(minute)
|
||||
self._timer_begins_calendar.select_day(date.day)
|
||||
self._timer_begins_calendar.select_month(date.month - 1, date.year)
|
||||
self._timer_begins_entry.set_text(
|
||||
"{}-{}-{} {}:{:02d}".format(date.year, date.month, date.day, hour, minute))
|
||||
|
||||
def get_ends_date(self):
|
||||
date = self._timer_ends_calendar.get_date()
|
||||
return datetime(year=date.year, month=date.month + 1, day=date.day,
|
||||
hour=int(self._timer_ends_hr_button.get_value()),
|
||||
minute=int(self._timer_ends_min_button.get_value()))
|
||||
|
||||
def set_ends_date(self, date):
|
||||
hour = date.hour
|
||||
minute = date.minute
|
||||
self._timer_ends_hr_button.set_value(hour)
|
||||
self._timer_ends_min_button.set_value(minute)
|
||||
self._timer_ends_calendar.select_day(date.day)
|
||||
self._timer_ends_calendar.select_month(date.month - 1, date.year)
|
||||
self._timer_ends_entry.set_text("{}-{}-{} {}:{:02d}".format(date.year, date.month, date.day, hour, minute))
|
||||
|
||||
def set_timer_for_add(self):
|
||||
self._timer_service_entry.set_text(self._timer_data.get("e2servicename", ""))
|
||||
self._timer_service_ref_entry.set_text(self._timer_data.get("e2servicereference", ""))
|
||||
date = datetime.now()
|
||||
self.set_begins_date(date)
|
||||
self.set_ends_date(date)
|
||||
self._timer_event_id_entry.set_text("")
|
||||
self._timer_location_switch.set_active(False)
|
||||
TimerTool.set_repetition_flags(0, self._days_buttons)
|
||||
|
||||
def set_timer_for_edit(self):
|
||||
self._timer_name_entry.set_text(self._timer_data.get("e2name", ""))
|
||||
self._timer_desc_entry.set_text(self._timer_data.get("e2description", "") or "")
|
||||
self._timer_service_entry.set_text(self._timer_data.get("e2servicename", "") or "")
|
||||
self._timer_service_ref_entry.set_text(self._timer_data.get("e2servicereference", ""))
|
||||
self._timer_event_id_entry.set_text(self._timer_data.get("e2eit", ""))
|
||||
self._timer_enabled_switch.set_active((self._timer_data.get("e2disabled", "0") == "0"))
|
||||
self._timer_action_combo_box.set_active_id(self._timer_data.get("e2justplay", "0"))
|
||||
self._timer_after_combo_box.set_active_id(self._timer_data.get("e2afterevent", "0"))
|
||||
self.set_time_data(int(self._timer_data.get("e2timebegin", "0")),
|
||||
int(self._timer_data.get("e2timeend", "0")))
|
||||
location = self._timer_data.get("e2location", "")
|
||||
self._timer_location_entry.set_text("" if location == "None" else location)
|
||||
TimerTool.set_repetition_flags(int(self._timer_data.get("e2repeated", "0")), self._days_buttons)
|
||||
|
||||
def set_timer_from_event_data(self):
|
||||
self._timer_name_entry.set_text(self._timer_data.get("e2eventtitle", ""))
|
||||
self._timer_desc_entry.set_text(self._timer_data.get("e2eventdescription", ""))
|
||||
self._timer_service_entry.set_text(self._timer_data.get("e2eventservicename", ""))
|
||||
self._timer_service_ref_entry.set_text(self._timer_data.get("e2eventservicereference", ""))
|
||||
self._timer_event_id_entry.set_text(self._timer_data.get("e2eventid", ""))
|
||||
self._timer_action_combo_box.set_active_id("1")
|
||||
self._timer_after_combo_box.set_active_id("3")
|
||||
start_time = int(self._timer_data.get("e2eventstart", "0"))
|
||||
self.set_time_data(start_time, start_time + int(self._timer_data.get("e2eventduration", "0")))
|
||||
|
||||
def set_time_data(self, start_time, end_time):
|
||||
""" Sets values for time widgets. """
|
||||
ev_time_start = datetime.fromtimestamp(start_time) or datetime.now()
|
||||
ev_time_end = datetime.fromtimestamp(end_time) or datetime.now()
|
||||
self._timer_begins_entry.set_text(ev_time_start.strftime(TimerTool.TIME_STR))
|
||||
self._timer_ends_entry.set_text(ev_time_end.strftime(TimerTool.TIME_STR))
|
||||
self._timer_begins_calendar.select_day(ev_time_start.day)
|
||||
self._timer_begins_calendar.select_month(ev_time_start.month - 1, ev_time_start.year)
|
||||
self._timer_ends_calendar.select_day(ev_time_end.day)
|
||||
self._timer_ends_calendar.select_month(ev_time_end.month - 1, ev_time_end.year)
|
||||
self._timer_begins_hr_button.set_value(ev_time_start.hour)
|
||||
self._timer_begins_min_button.set_value(ev_time_start.minute)
|
||||
self._timer_ends_hr_button.set_value(ev_time_end.hour)
|
||||
self._timer_ends_min_button.set_value(ev_time_end.minute)
|
||||
|
||||
def get_timer_data(self):
|
||||
""" Returns timer data as a dict. """
|
||||
return {"sRef": self._timer_service_ref_entry.get_text(),
|
||||
"begin": int(
|
||||
datetime.strptime(self._timer_begins_entry.get_text(), TimerTool.TIME_STR).timestamp()),
|
||||
"end": int(datetime.strptime(self._timer_ends_entry.get_text(), TimerTool.TIME_STR).timestamp()),
|
||||
"name": self._timer_name_entry.get_text(),
|
||||
"description": self._timer_desc_entry.get_text(),
|
||||
"dirname": "",
|
||||
"eit": self._timer_event_id_entry.get_text(),
|
||||
"disabled": int(not self._timer_enabled_switch.get_active()),
|
||||
"justplay": self._timer_action_combo_box.get_active_id(),
|
||||
"afterevent": self._timer_after_combo_box.get_active_id(),
|
||||
"repeated": TimerTool.get_repetition_flags(self._days_buttons)}
|
||||
|
||||
def __init__(self, app, http_api, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self._http_api = http_api
|
||||
self._app = app
|
||||
self._app.connect("page-changed", self.update_timer_list)
|
||||
# Icon.
|
||||
theme = Gtk.IconTheme.get_default()
|
||||
icon = "alarm-symbolic"
|
||||
self._icon = theme.load_icon(icon, 16, 0) if theme.lookup_icon(icon, 16, 0) else None
|
||||
|
||||
handlers = {}
|
||||
handlers = {"on_timer_add": self.on_timer_add,
|
||||
"on_timer_edit": self.on_timer_edit,
|
||||
"on_timer_remove": self.on_timer_remove,
|
||||
"on_timers_press": self.on_timers_press,
|
||||
"on_timers_key_press": self.on_timers_key_press,
|
||||
"on_timer_cursor_changed": self.on_timer_cursor_changed,
|
||||
"on_timers_drag_data_received": self.on_timers_drag_data_received}
|
||||
|
||||
builder = get_builder(UI_RESOURCES_PATH + "control.glade", handlers, objects=("timers_frame", "timer_model"))
|
||||
self._view = builder.get_object("timer_view")
|
||||
self._remove_button = builder.get_object("timer_remove_button")
|
||||
self._remove_button.bind_property("sensitive", builder.get_object("timer_edit_button"), "sensitive")
|
||||
self._info_button = builder.get_object("timer_info_check_button")
|
||||
self._info_button.bind_property("active", builder.get_object("timer_info_frame"), "visible")
|
||||
self._info_enabled_switch = builder.get_object("timer_info_enabled_switch")
|
||||
self._ref_info_label = builder.get_object("timer_ref_value_label")
|
||||
self._event_id_info_label = builder.get_object("timer_event_id_value_label")
|
||||
self._begins_info_label = builder.get_object("timer_begins_value_label")
|
||||
self._ends_info_label = builder.get_object("timer_ends_value_label")
|
||||
self._action_info_label = builder.get_object("timer_action_value_label")
|
||||
self._after_info_label = builder.get_object("timer_after_value_label")
|
||||
self._timer_location_switch = builder.get_object("timer_location_switch")
|
||||
self._info_location_entry = builder.get_object("timer_info_location_entry")
|
||||
self._days_buttons = (builder.get_object("timer_info_mo_check_button"),
|
||||
builder.get_object("timer_info_tu_check_button"),
|
||||
builder.get_object("timer_info_we_check_button"),
|
||||
builder.get_object("timer_info_th_check_button"),
|
||||
builder.get_object("timer_info_fr_check_button"),
|
||||
builder.get_object("timer_info_sa_check_button"),
|
||||
builder.get_object("timer_info_su_check_button"))
|
||||
# Disable button presses.
|
||||
list(map(lambda b: b.connect("button-press-event", lambda bx, e: True), self._days_buttons))
|
||||
self._info_enabled_switch.connect("button-press-event", lambda b, e: True)
|
||||
# DnD initialization for the timer list.
|
||||
self._view.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
|
||||
self._view.drag_dest_add_text_targets()
|
||||
|
||||
self.pack_start(builder.get_object("timers_frame"), True, True, 0)
|
||||
self.show()
|
||||
|
||||
def update_timer_list(self, app, page):
|
||||
if page is Page.TIMERS:
|
||||
self._app._wait_dialog.show()
|
||||
self._app.wait_dialog.show()
|
||||
self._http_api.send(HttpAPI.Request.TIMER_LIST, "", self.update_timers_data)
|
||||
|
||||
@run_idle
|
||||
@@ -111,10 +417,11 @@ class TimersBox(Gtk.Box):
|
||||
model = self._view.get_model()
|
||||
model.clear()
|
||||
list(map(model.append, (self.get_timer_row(t) for t in timers.get("timer_list", []))))
|
||||
self._remove_button.set_visible(len(model))
|
||||
self._app._wait_dialog.hide()
|
||||
self._remove_button.set_sensitive(len(model))
|
||||
self._app.wait_dialog.hide()
|
||||
|
||||
def get_timer_row(self, timer):
|
||||
disabled = self._icon if timer.get("e2disabled", "0") == "0" else None
|
||||
name = timer.get("e2name", "") or ""
|
||||
description = timer.get("e2description", "") or ""
|
||||
service = timer.get("e2servicename", "") or ""
|
||||
@@ -122,10 +429,198 @@ class TimersBox(Gtk.Box):
|
||||
end_time = datetime.fromtimestamp(int(timer.get("e2timeend", "0")))
|
||||
time = "{} - {}".format(start_time.strftime("%A, %H:%M"), end_time.strftime("%H:%M"))
|
||||
|
||||
return name, service, time, description, timer
|
||||
return disabled, name, service, time, description, timer
|
||||
|
||||
def on_timer_add(self, timer=None, value=None):
|
||||
model, paths = self._app.fav_view.get_selection().get_selected_rows()
|
||||
p_count = len(paths)
|
||||
|
||||
if p_count == 1:
|
||||
service = self._app.current_services.get(model[paths][Column.FAV_ID], None)
|
||||
if service:
|
||||
self.add_timer({"e2servicename": service.service,
|
||||
"e2servicereference": service.picon_id.rstrip(".png").replace("_", ":")})
|
||||
elif p_count > 1:
|
||||
self._app.show_error_message("Please, select only one item!")
|
||||
else:
|
||||
self._app.show_error_message("No selected item!")
|
||||
|
||||
def add_timer(self, timer_data):
|
||||
dialog = self.TimerDialog(self.TimerAction.ADD, timer_data)
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
self._http_api.send(HttpAPI.Request.TIMER, dialog.request, self.timer_add_edit_callback)
|
||||
dialog.destroy()
|
||||
|
||||
def on_timer_edit(self, action=None, value=None):
|
||||
model, paths = self._view.get_selection().get_selected_rows()
|
||||
if len(paths) > 1:
|
||||
self._app.show_error_message("Please, select only one item!")
|
||||
return
|
||||
|
||||
dialog = self.TimerDialog(self.TimerAction.CHANGE, model[paths][-1])
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
self._http_api.send(HttpAPI.Request.TIMER, dialog.request, self.timer_add_edit_callback)
|
||||
dialog.destroy()
|
||||
|
||||
@run_idle
|
||||
def timer_add_edit_callback(self, resp):
|
||||
if "error_code" in resp:
|
||||
msg = "Error getting timer status.\n{}".format(resp.get("error_code"))
|
||||
self._app.show_error_message(msg)
|
||||
log(msg)
|
||||
return
|
||||
|
||||
state = resp.get("e2state", None)
|
||||
if state == "False":
|
||||
msg = resp.get("e2statetext", "")
|
||||
self._app.show_error_message(msg)
|
||||
log(msg)
|
||||
if state == "True":
|
||||
msg = resp.get("e2statetext", "")
|
||||
log(msg)
|
||||
self._app.show_info_message(msg, Gtk.MessageType.INFO)
|
||||
self.update_timer_list(self._app, Page.TIMERS)
|
||||
else:
|
||||
log("Error getting timer status. No response!")
|
||||
|
||||
def on_timer_remove(self, action=None, value=None):
|
||||
model, paths = self._view.get_selection().get_selected_rows()
|
||||
if not paths or show_dialog(DialogType.QUESTION, self._app.app_window) != Gtk.ResponseType.OK:
|
||||
return
|
||||
|
||||
refs = {}
|
||||
for path in paths:
|
||||
timer = model[path][-1]
|
||||
ref = "timerdelete?sRef={}&begin={}&end={}".format(quote(timer.get("e2servicereference", "")),
|
||||
timer.get("e2timebegin", ""),
|
||||
timer.get("e2timeend", ""))
|
||||
refs[ref] = model.get_iter(path)
|
||||
|
||||
self._app.wait_dialog.show("Deleting data...")
|
||||
gen = self.remove_timers(refs)
|
||||
GLib.idle_add(lambda: next(gen, False))
|
||||
|
||||
def remove_timers(self, refs):
|
||||
tasks = list(refs)
|
||||
removed = set()
|
||||
for ref in refs:
|
||||
yield from self.remove_timer(ref, removed, tasks)
|
||||
|
||||
while tasks:
|
||||
yield True
|
||||
|
||||
model = self._view.get_model()
|
||||
list(map(model.remove, (refs[ref] for ref in refs if ref in removed)))
|
||||
self._app.wait_dialog.hide()
|
||||
self._remove_button.set_sensitive(len(model))
|
||||
yield True
|
||||
|
||||
def remove_timer(self, ref, removed, tasks=None):
|
||||
def callback(resp):
|
||||
if resp.get("e2state", "") == "True":
|
||||
log(resp.get("e2statetext", ""))
|
||||
removed.add(ref)
|
||||
else:
|
||||
log(resp.get("e2statetext", None) or "Timer deletion error.")
|
||||
if tasks:
|
||||
tasks.pop()
|
||||
|
||||
self._http_api.send(HttpAPI.Request.TIMER, ref, callback)
|
||||
yield True
|
||||
|
||||
def on_timers_press(self, view, event):
|
||||
if event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS and len(view.get_model()) > 0:
|
||||
self.on_timer_edit()
|
||||
|
||||
def on_timers_key_press(self, view, event):
|
||||
key_code = event.hardware_keycode
|
||||
if not KeyboardKey.value_exist(key_code):
|
||||
return
|
||||
|
||||
key = KeyboardKey(key_code)
|
||||
if key is KeyboardKey.DELETE:
|
||||
self.on_timer_remove()
|
||||
|
||||
def on_timer_cursor_changed(self, view):
|
||||
path, column = view.get_cursor()
|
||||
if not path:
|
||||
return
|
||||
|
||||
timer = view.get_model()[path][-1]
|
||||
self._info_enabled_switch.set_active((timer.get("e2disabled", "0") == "0"))
|
||||
self._ref_info_label.set_text(timer.get("e2servicereference", ""))
|
||||
self._event_id_info_label.set_text(timer.get("e2eit", ""))
|
||||
self._action_info_label.set_text(get_message(self.ACTION.get(timer.get("e2justplay", "0"), "0")))
|
||||
self._after_info_label.set_text(get_message(self.AFTER_EVENT.get(timer.get("e2afterevent", "0"), "0")))
|
||||
self._begins_info_label.set_text(str(datetime.fromtimestamp(int(timer.get("e2timebegin", "0")))))
|
||||
self._ends_info_label.set_text(str(datetime.fromtimestamp(int(timer.get("e2timeend", "0")))))
|
||||
self.set_repetition_flags(int(timer.get("e2repeated", "0")), self._days_buttons)
|
||||
location = timer.get("e2location", "")
|
||||
self._info_location_entry.set_text("" if location == "None" else location)
|
||||
|
||||
@staticmethod
|
||||
def get_repetition_flags(boxes):
|
||||
""" Returns flags for repetition.
|
||||
|
||||
@param boxes: Buttons tuple for the days of the week.
|
||||
"""
|
||||
day_flags = 0
|
||||
for i, box in enumerate(boxes):
|
||||
if box.get_active():
|
||||
day_flags = day_flags | (1 << i)
|
||||
|
||||
return day_flags
|
||||
|
||||
@staticmethod
|
||||
def set_repetition_flags(flags, boxes):
|
||||
""" Sets flags for repetition.
|
||||
|
||||
@param flags: Flags value.
|
||||
@param boxes: Buttons tuple for the days of the week.
|
||||
"""
|
||||
for i, box in enumerate(boxes):
|
||||
box.set_active(flags & 1 == 1)
|
||||
flags = flags >> 1
|
||||
|
||||
# ***************** Drag-and-drop ********************* #
|
||||
|
||||
def on_timers_drag_data_received(self, box, context, x, y, data, info, time):
|
||||
txt = data.get_text()
|
||||
if txt:
|
||||
itr_str, sep, source = txt.partition(self._app.DRAG_SEP)
|
||||
if not source:
|
||||
return
|
||||
|
||||
itrs = itr_str.split(",")
|
||||
if len(itrs) > 1:
|
||||
self._app.show_error_message("Please, select only one item!")
|
||||
return
|
||||
|
||||
fav_id = None
|
||||
if source == self._app.FAV_MODEL_NAME:
|
||||
model = self._app.fav_view.get_model()
|
||||
fav_id = model.get_value(model.get_iter_from_string(itrs[0]), Column.FAV_ID)
|
||||
elif source == self._app.SERVICE_MODEL_NAME:
|
||||
model = self._app.services_view.get_model()
|
||||
fav_id = model.get_value(model.get_iter_from_string(itrs[0]), Column.SRV_FAV_ID)
|
||||
|
||||
service = self._app.current_services.get(fav_id, None)
|
||||
if service:
|
||||
if service.service_type == BqServiceType.ALT.name:
|
||||
msg = "Alternative service.\n\n {}".format(get_message("Not implemented yet!"))
|
||||
show_dialog(DialogType.ERROR, transient=self._app._main_window, text=msg)
|
||||
context.finish(False, False, time)
|
||||
return
|
||||
|
||||
self.add_timer({"e2servicename": service.service,
|
||||
"e2servicereference": service.picon_id.rstrip(".png").replace("_", ":")})
|
||||
|
||||
context.finish(True, False, time)
|
||||
|
||||
|
||||
class RecordingsBox(Gtk.Box):
|
||||
class RecordingsTool(Gtk.Box):
|
||||
ROOT = ".."
|
||||
DEFAULT_PATH = "/hdd"
|
||||
|
||||
@@ -276,7 +771,7 @@ class RecordingsBox(Gtk.Box):
|
||||
self._rec_view.get_column(c).set_visible(state)
|
||||
|
||||
|
||||
class ControlBox(Gtk.Box):
|
||||
class ControlTool(Gtk.Box):
|
||||
|
||||
def __init__(self, app, http_api, settings, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -48,7 +48,7 @@ from app.eparser.neutrino.bouquets import BqType
|
||||
from app.settings import (SettingsType, Settings, SettingsException, SettingsReadException,
|
||||
IS_DARWIN, PlayStreamsMode)
|
||||
from app.tools.media import Recorder
|
||||
from app.ui.control import ControlBox, EpgBox, TimersBox, RecordingsBox
|
||||
from app.ui.control import ControlTool, EpgTool, TimerTool, RecordingsTool
|
||||
from app.ui.epg import EpgDialog
|
||||
from app.ui.ftp import FtpClientBox
|
||||
from app.ui.playback import PlayerBox
|
||||
@@ -253,6 +253,8 @@ class Application(Gtk.Application):
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("page-changed", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("change-page", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("play-recording", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("play-current", self, GObject.SIGNAL_RUN_LAST,
|
||||
@@ -379,6 +381,7 @@ class Application(Gtk.Application):
|
||||
self._stack_recordings_box = builder.get_object("recordings_box")
|
||||
self._stack_ftp_box = builder.get_object("ftp_box")
|
||||
self._stack_control_box = builder.get_object("control_box")
|
||||
self.connect("change-page", self.on_page_change)
|
||||
# Header bar.
|
||||
profile_box = builder.get_object("profile_combo_box")
|
||||
toolbar_box = builder.get_object("toolbar_main_box")
|
||||
@@ -707,13 +710,13 @@ class Application(Gtk.Application):
|
||||
|
||||
if self._services_load_spinner.get_property("active"):
|
||||
msg = "{}\n\n\t{}".format(get_message("Data loading in progress!"), get_message("Are you sure?"))
|
||||
if show_dialog(DialogType.QUESTION, self._main_window, msg) == Gtk.ResponseType.CANCEL:
|
||||
if show_dialog(DialogType.QUESTION, self._main_window, msg) != Gtk.ResponseType.OK:
|
||||
return True
|
||||
|
||||
if self._recorder:
|
||||
if self._recorder.is_record():
|
||||
msg = "{}\n\n\t{}".format(get_message("Recording in progress!"), get_message("Are you sure?"))
|
||||
if show_dialog(DialogType.QUESTION, self._main_window, msg) == Gtk.ResponseType.CANCEL:
|
||||
if show_dialog(DialogType.QUESTION, self._main_window, msg) != Gtk.ResponseType.OK:
|
||||
return True
|
||||
self._recorder.release()
|
||||
|
||||
@@ -757,15 +760,15 @@ class Application(Gtk.Application):
|
||||
box.pack_start(self._picon_manager, True, True, 0)
|
||||
|
||||
def on_epg_realize(self, box):
|
||||
self._epg_box = EpgBox(self, self._http_api)
|
||||
self._epg_box = EpgTool(self, self._http_api)
|
||||
box.pack_start(self._epg_box, True, True, 0)
|
||||
|
||||
def on_timers_realize(self, box):
|
||||
self._epg_box = TimersBox(self, self._http_api)
|
||||
self._epg_box = TimerTool(self, self._http_api)
|
||||
box.pack_start(self._epg_box, True, True, 0)
|
||||
|
||||
def on_recordings_realize(self, box):
|
||||
self._recordings_box = RecordingsBox(self, self._http_api, self._settings)
|
||||
self._recordings_box = RecordingsTool(self, self._http_api, self._settings)
|
||||
box.pack_start(self._recordings_box, True, True, 0)
|
||||
self._player_box.connect("play", self._recordings_box.on_playback)
|
||||
self._player_box.connect("playback-close", self._recordings_box.on_playback_close)
|
||||
@@ -775,7 +778,7 @@ class Application(Gtk.Application):
|
||||
box.pack_start(self._ftp_client, True, True, 0)
|
||||
|
||||
def on_control_realize(self, box: Gtk.HBox):
|
||||
self._control_box = ControlBox(self, self._http_api, self._settings)
|
||||
self._control_box = ControlTool(self, self._http_api, self._settings)
|
||||
box.pack_start(self._control_box, True, True, 0)
|
||||
|
||||
def on_visible_page(self, stack, param):
|
||||
@@ -788,6 +791,9 @@ class Application(Gtk.Application):
|
||||
action.set_state(value)
|
||||
self._settings.add(action.get_name(), bool(value))
|
||||
|
||||
def on_page_change(self, app, page_name):
|
||||
self._stack.set_visible_child_name(page_name)
|
||||
|
||||
# ***************** Copy - Cut - Paste ********************* #
|
||||
|
||||
def on_services_copy(self, view):
|
||||
@@ -3450,6 +3456,10 @@ class Application(Gtk.Application):
|
||||
def app_settings(self):
|
||||
return self._settings
|
||||
|
||||
@property
|
||||
def wait_dialog(self):
|
||||
return self._wait_dialog
|
||||
|
||||
@property
|
||||
def http_api(self):
|
||||
return self._http_api
|
||||
|
||||
Reference in New Issue
Block a user