Compare commits

...

35 Commits
0.2.1 ... 0.2.3

Author SHA1 Message Date
Dmitriy Yefremov
0daaf6d1e5 neutrino save services fix 2018-02-11 10:50:21 +03:00
DYefremov
47f26b0f4c little fix 2018-02-10 15:49:44 +03:00
DYefremov
e67ce41667 copy/paste fix 2018-02-06 14:20:59 +03:00
DYefremov
0cff24486a insert marker to empty bouquet fix 2018-02-06 13:56:17 +03:00
DYefremov
850ba0d96a little ui changes 2018-02-06 09:49:51 +03:00
Dmitriy Yefremov
303c9a0267 write bouquet fix 2018-02-05 22:17:06 +03:00
Dmitriy Yefremov
0f95165088 set encoding for ftp, fix file names for bouquets 2018-02-05 18:24:49 +03:00
Dmitriy Yefremov
105cf9c90c new algorithm for picons retrieving 2018-02-05 14:44:42 +03:00
Dmitriy Yefremov
cb40a8d0de name space for picons 2018-02-04 18:09:37 +03:00
DYefremov
f19ab37bc8 sat position for picons dialog 2018-02-03 23:25:15 +03:00
DYefremov
d716bd6a86 Displaying picons in lists for Neutrino 2018-02-03 21:07:01 +03:00
Dmitriy Yefremov
5b13b22823 lamedb fix 2018-02-03 17:23:16 +03:00
Dmitriy Yefremov
49076fe477 bouquet names fix 2018-02-03 16:45:54 +03:00
DYefremov
50a517b6f1 simple skeleton for global search 2018-02-02 12:45:58 +03:00
Dmitriy Yefremov
184c3b18ba assign picon skeleton 2018-02-01 21:43:44 +03:00
Dmitriy Yefremov
2f8dcaf47b data backup before save 2018-02-01 14:02:59 +03:00
Dmitriy Yefremov
dbe18b345f skeleton for picon remove 2018-02-01 13:10:06 +03:00
Dmitriy Yefremov
5d68ec8176 added search bar 2018-01-31 16:02:26 +03:00
DYefremov
83e58f9375 little decoupling, filter bar 2018-01-31 00:13:42 +03:00
Dmitriy Yefremov
fe199d78a4 picon reference 2018-01-30 12:37:04 +03:00
DYefremov
d5f7acb019 popup menus for picons 2018-01-29 18:07:47 +03:00
DYefremov
a141c34ee7 Display picons in the fav list 2018-01-29 14:46:34 +03:00
Dmitriy Yefremov
25c9189e1a Display picons in the services list 2018-01-28 23:10:54 +03:00
Dmitriy Yefremov
d9390aa7be Update README.md 2018-01-26 21:26:03 +03:00
Dmitriy Yefremov
e12cc86e5f Update readme 2018-01-26 21:21:40 +03:00
DYefremov
f1ef9fe4aa decoupling deletion, deletion with considering filter 2018-01-26 15:15:39 +03:00
Dmitriy Yefremov
728bfd0b20 added remove selection keys 2018-01-25 21:43:48 +03:00
Dmitriy Yefremov
1d6022b6db fix lock\hide 2018-01-25 21:05:24 +03:00
DYefremov
8609d30ac9 bouquets fix, new implementation of services filter 2018-01-25 16:11:52 +03:00
DYefremov
fde06dca89 filter revert 2018-01-24 13:39:11 +03:00
Dmitriy Yefremov
e41bf5f58f little gui changes 2018-01-24 00:05:15 +03:00
Dmitriy Yefremov
b1488df9ce little gui changes 2018-01-23 22:58:43 +03:00
DYefremov
c6e4b3624b services filter skeleton 2018-01-23 16:18:28 +03:00
DYefremov
26b843921b force ctrl for fav and services lists 2018-01-22 14:51:34 +03:00
Dmitriy Yefremov
e73638d006 resize option for picons 2018-01-20 22:17:18 +03:00
18 changed files with 1234 additions and 329 deletions

View File

@@ -5,14 +5,17 @@ Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
Keyboard shortcuts:
Ctrl + X, C, V, Up, Down, PageUp, PageDown, S, T, E, L, H, Space; Insert, Delete, F2.
Ctrl + X, C, V, Up, Down, PageUp, PageDown, S, T, E, L, H, Space; Insert, Delete, F2.
Insert - copies the selected channels from the main list to the bouquet or inserts (creates) a new bouquet.
Ctrl + X - only in bouquet list. Ctrl + C - only in services list.
Clipboard is "rubber". There is an accumulation before the insertion!
Ctrl + E, F2 - edit/rename.
Ctrl + S, T, E in Satellites edit tool for create and edit satellite or transponder.
Ctrl + L - parental lock.
Ctrl + L - parental lock.
Ctrl + H - hide/skip.
Left/Right - remove selection.
Multiple selections in lists only with Space key (as in file managers)!
Extra:
Ability to import IPTV into bouquet from m3u files(Enigma2 only)!

View File

@@ -2,8 +2,8 @@
from collections import namedtuple
from enum import Enum
Service = namedtuple("Service", ["flags_cas", "transponder_type", "coded", "service", "locked", "hide",
"package", "service_type", "ssid", "freq", "rate", "pol", "fec",
Service = namedtuple("Service", ["flags_cas", "transponder_type", "coded", "service", "locked", "hide", "package",
"service_type", "picon", "picon_id", "ssid", "freq", "rate", "pol", "fec",
"system", "pos", "data_id", "fav_id", "transponder"])
@@ -61,7 +61,7 @@ SYSTEM = {"0": "DVB-S", "1": "DVB-S2"}
MODULATION = {"0": "Auto", "1": "QPSK", "2": "8PSK", "3": "16APSK", "5": "32APSK"}
SERVICE_TYPE = {"-2": "Unknown", "1": "TV", "2": "Radio", "3": "Data",
"10": "Radio", "12": "Data", "22": "TV", "25": "TV (HD)",
"10": "Radio", "12": "Data", "22": "TV", "25": "TV (HD)", "31": "TV (UHD)",
"136": "Data", "139": "Data"}
CAS = {"C:2600": "BISS", "C:0b00": "Conax", "C:0b01": "Conax", "C:0b02": "Conax", "C:0baa": "Conax", "C:0602": "Irdeto",

View File

@@ -1,7 +1,6 @@
""" Module for parsing bouquets """
from app.eparser.ecommons import BqServiceType, BouquetService, Bouquets, Bouquet
_BOUQUETS_PATH = "../data/"
_TV_ROOT_FILE_NAME = "bouquets.tv"
_RADIO_ROOT_FILE_NAME = "bouquets.radio"
@@ -19,10 +18,10 @@ def write_bouquets(path, bouquets):
line.append("#NAME {}\n".format(bqs.name))
for bq in bqs.bouquets:
line.append(srv_line.format(bq.name, bq.type))
line.append(srv_line.format(bq.name.replace(" ", "_"), bq.type))
write_bouquet(path, bq.name, bq.type, bq.services)
with open(path + "bouquets.{}".format(bqs.type), "w") as file:
with open(path + "bouquets.{}".format(bqs.type), "w", encoding="utf-8") as file:
file.writelines(line)
@@ -38,40 +37,36 @@ def write_bouquet(path, name, bq_type, channels):
else:
bouquet.append("#SERVICE {}\n".format(to_bouquet_id(ch)))
with open(path + "userbouquet.{}.{}".format(name, bq_type), "w") as file:
with open(path + "userbouquet.{}.{}".format(name.replace(" ", "_"), bq_type), "w", encoding="utf-8") as file:
file.writelines(bouquet)
def to_bouquet_id(ch):
""" Creates bouquet channel id """
data_type = ch.data_id
if data_type:
data_type = int(ch.data_id.split(":")[-2])
if data_type == 22:
data_type = 16
elif data_type == 25:
data_type = 19
service = "{}:0:{}:{}:0:0:0:".format(1, data_type, ch.fav_id)
if data_type and len(data_type) > 4:
data_type = int(ch.data_id.split(":")[4])
return service
return "{}:0:{:X}:{}:0:0:0:".format(1, data_type, ch.fav_id)
def get_bouquet(path, name, bq_type):
""" Parsing services ids from bouquet file """
with open(path + "userbouquet.{}.{}".format(name, bq_type)) as file:
with open(path + "userbouquet.{}.{}".format(name, bq_type), encoding="utf-8") as file:
chs_list = file.read()
services = []
for ch in list(filter(lambda x: len(x) > 1, chs_list.split("#SERVICE")[1:])): # filtering ['']
srvs = list(filter(None, chs_list.split("\n#SERVICE"))) # filtering ['']
for ch in srvs[1:]:
ch_data = ch.strip().split(":")
if ch_data[1] == "64":
services.append(BouquetService(ch_data[-1].split("\n")[0], BqServiceType.MARKER, ch, ch_data[2]))
elif "http" in ch:
services.append(BouquetService(ch_data[-1].split("\n")[0], BqServiceType.IPTV, ch, 0))
else:
services.append(BouquetService(None, BqServiceType.DEFAULT,
"{}:{}:{}:{}".format(ch_data[3], ch_data[4], ch_data[5], ch_data[6]), 0))
fav_id = "{}:{}:{}:{}".format(ch_data[3], ch_data[4], ch_data[5], ch_data[6])
services.append(BouquetService(None, BqServiceType.DEFAULT, fav_id, 0))
return services
return srvs[0].strip("#NAME").strip(), services
def parse_bouquets(path, bq_name, bq_type):
@@ -85,10 +80,10 @@ def parse_bouquets(path, bq_name, bq_type):
_, _, name = line.partition(nm_sep)
bouquets = Bouquets(name.strip(), bq_type, [])
if bouquets and "#SERVICE" in line:
name = line.split(".")[1]
bouquets[2].append(Bouquet(name=name,
b_name, services = get_bouquet(path, line.split(".")[1], bq_type)
bouquets[2].append(Bouquet(name=b_name,
type=bq_type,
services=get_bouquet(path, name, bq_type),
services=services,
locked=None,
hidden=None))

View File

@@ -9,7 +9,6 @@ from .blacklist import get_blacklist
from ..ecommons import Service, POLARIZATION, SYSTEM, FEC, SERVICE_TYPE, FLAG
_HEADER = "eDVB services /4/"
_FILE_PATH = "../data/lamedb"
_SEP = ":" # separator
_FILE_NAME = "lamedb"
@@ -57,7 +56,7 @@ def parse(path):
log(msg)
raise SyntaxError(msg)
transponders, sep, services = services.partition("services") # 2 step
services, sep, _ = services.partition("end") # 3 step
services, sep, _ = services.partition("\nend") # 3 step
return parse_services(services.split("\n"), transponders.split("/"), path)
@@ -86,9 +85,19 @@ def parse_services(services, transponders, path):
for ch in srv:
data = str(ch[0]).split(_SEP)
sp = "0"
tid = data[2]
nid = data[3]
transponder_id = "{}:{}:{}".format(data[1], tid, nid)
transponder = transponders.get(transponder_id, None)
tid = tid.lstrip(sp).upper()
nid = nid.lstrip(sp).upper()
ssid = str(data[0]).lstrip(sp).upper()
onid = str(data[1]).lstrip(sp).upper()
# For comparison in bouquets. Needed in upper case!!!
fav_id = "{}:{}:{}:{}".format(str(data[0]).lstrip(sp), str(data[2]).lstrip(sp),
str(data[3]).lstrip(sp), str(data[1]).lstrip(sp)).upper()
fav_id = "{}:{}:{}:{}".format(ssid, tid, nid, onid)
picon_id = "1_0_{}_{}_{}_{}_{}_0_0_0.png".format(1, ssid, tid, nid, onid)
all_flags = ch[2].split(",")
coded = CODED_ICON if list(filter(lambda x: x.startswith("C:"), all_flags)) else None
flags = list(filter(lambda x: x.startswith("f:"), all_flags))
@@ -98,21 +107,22 @@ def parse_services(services, transponders, path):
package = list(filter(lambda x: x.startswith("p:"), all_flags))
package = package[0][2:] if package else None
transponder_id = "{}:{}:{}".format(data[1], data[2], data[3])
transponder = transponders.get(transponder_id, None)
if transponder is not None:
tr_type, sp, tr = str(transponder).partition(" ")
tr = tr.split(_SEP)
service_type = SERVICE_TYPE.get(data[4], SERVICE_TYPE["-2"])
# removing all non printable symbols!
srv_name = "".join(c for c in ch[1] if c.isprintable())
channels.append(Service(flags_cas=ch[2],
transponder_type=tr_type,
coded=coded,
service=ch[1],
service=srv_name,
locked=locked,
hide=hide,
package=package,
service_type=service_type,
picon=None,
picon_id=picon_id,
ssid=data[0],
freq=tr[0],
rate=tr[1],

View File

@@ -3,7 +3,7 @@ from .ecommons import BqServiceType, Service
def parse_m3u(path):
with open(path) as file:
aggr = [None] * 8
aggr = [None] * 10
channels = []
count = 0
name = None
@@ -15,7 +15,8 @@ def parse_m3u(path):
count = 0
fav_id = " 1:0:1:0:0:0:0:0:0:0:{}:{}\n#DESCRIPTION: {}\n".format(
line.strip().replace(":", "%3a"), name, name, None)
channels.append(Service(*aggr[0:3], name, *aggr[0:3], BqServiceType.IPTV.name, *aggr, fav_id, None))
srv = Service(*aggr[0:3], name, *aggr[0:3], BqServiceType.IPTV.name, *aggr, fav_id, None)
channels.append(srv)
return channels

View File

@@ -53,8 +53,8 @@ def write_services(path, services):
for srv in transponers.get(tr):
srv_elem = doc.createElement("S")
srv_elem.setAttribute("i", srv[8])
srv_elem.setAttribute("n", srv[3])
srv_elem.setAttribute("i", srv.ssid)
srv_elem.setAttribute("n", srv.service)
srv_attrs = srv.data_id.split(":")
api = srv_attrs.pop(0)
@@ -116,9 +116,7 @@ def parse_transponder(api, sat, sat_pos, services, tr_elem):
sys = sys.value if sys else sys
tr = "{}:{}:{}:{}:{}:{}:{}:{}:{}".format(tr_id, on, freq, inv, rate, fec, pol, mod, sys)
tr_id = tr_id.lstrip("0")
on = on.lstrip("0")
for srv_elem in tr_elem.getElementsByTagName("S"):
if srv_elem.hasAttributes():
@@ -141,7 +139,8 @@ def parse_transponder(api, sat, sat_pos, services, tr_elem):
vt = srv_elem.attributes["vt"].value
data_id = "{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}".format(api, srv_type, sys, num, f, v, a, p, pmt, tx, vt)
fav_id = "{}:{}:{}".format(tr_id, on, ssid.lstrip("0"))
fav_id = "{}:{}:{}".format(tr_id, on.lstrip("0"), ssid.lstrip("0"))
picon_id = "{}{}{}.png".format(tr_id, on, ssid)
srv = Service(flags_cas=sat,
transponder_type=None,
@@ -151,6 +150,8 @@ def parse_transponder(api, sat, sat_pos, services, tr_elem):
hide=None,
package=PROVIDER.get(int(on, 16)),
service_type=SERVICE_TYPE.get(str(int(srv_type, 16))),
picon=None,
picon_id=picon_id,
ssid=ssid,
freq=freq,
rate=rate,

View File

@@ -22,6 +22,7 @@ class DownloadDataType(Enum):
def download_data(*, properties, download_type=DownloadDataType.ALL, callback=None):
with FTP(host=properties["host"]) as ftp:
ftp.login(user=properties["user"], passwd=properties["password"])
ftp.encoding = "utf-8"
save_path = properties["data_dir_path"]
os.makedirs(os.path.dirname(save_path), exist_ok=True)
files = []
@@ -66,6 +67,7 @@ def upload_data(*, properties, download_type=DownloadDataType.ALL, remove_unused
with FTP(host=host) as ftp:
ftp.login(user=properties["user"], passwd=properties["password"])
ftp.encoding = "utf-8"
if download_type is DownloadDataType.ALL or download_type is DownloadDataType.SATELLITES:
ftp.cwd(properties["satellites_xml_path"])

View File

@@ -6,7 +6,10 @@ from html.parser import HTMLParser
from app.commons import log
from app.properties import Profile
Provider = namedtuple("Provider", ["logo", "name", "url", "on_id", "selected"])
_ENIGMA2_PICON_KEY = "{:X}:{:X}:{:X}0000"
_NEUTRINO_PICON_KEY = "{:x}{:04x}{:04x}.png"
Provider = namedtuple("Provider", ["logo", "name", "pos", "url", "on_id", "selected"])
Picon = namedtuple("Picon", ["ref", "ssid", "v_pid"])
@@ -68,7 +71,7 @@ class PiconsParser(HTMLParser):
pass
@staticmethod
def parse(open_path, picons_path, tmp_path, on_id, profile=Profile.ENIGMA_2):
def parse(open_path, picons_path, tmp_path, on_id, pos, picon_ids, profile=Profile.ENIGMA_2):
with open(open_path, encoding="utf-8", errors="replace") as f:
parser = PiconsParser()
parser.reset()
@@ -78,19 +81,20 @@ class PiconsParser(HTMLParser):
os.makedirs(picons_path, exist_ok=True)
for p in picons:
try:
picon_file_name = picons_path + PiconsParser.format(p.ssid, on_id, p.v_pid, profile)
shutil.copyfile(tmp_path + "www.lyngsat.com/" + p.ref.lstrip("."), picon_file_name)
name = PiconsParser.format(p.ssid, on_id, p.v_pid, pos, picon_ids, profile)
p_name = picons_path + (name if name else os.path.basename(p.ref))
shutil.copyfile(tmp_path + "www.lyngsat.com/" + p.ref.lstrip("."), p_name)
except (TypeError, ValueError) as e:
log("Picons format parse error: {} {} {}".format(p.ref, p.ssid, p.v_pid) + "\n" + str(e))
log("Picons format parse error: {}".format(p) + "\n" + str(e))
print(e)
@staticmethod
def format(ssid, on_id, v_pid, profile: Profile):
def format(ssid, on_id, v_pid, pos, picon_ids, profile: Profile):
tr_id = int(ssid[:-2] if len(ssid) < 4 else ssid[:2])
if profile is Profile.ENIGMA_2:
return "1_0_{}_{:X}_{:X}_{:X}_1680000_0_0_0.png".format(1 if v_pid else 2, int(ssid), tr_id, int(on_id))
return picon_ids.get(_ENIGMA2_PICON_KEY.format(int(ssid), int(on_id), int(pos)), None)
elif profile is Profile.NEUTRINO_MP:
return "{:x}{:04x}{:04x}.png".format(tr_id, int(on_id), int(ssid))
return _NEUTRINO_PICON_KEY.format(tr_id, int(on_id), int(ssid))
else:
return "{}.png".format(ssid)
@@ -112,6 +116,8 @@ class ProviderParser(HTMLParser):
self._current_cell = []
self.rows = []
self._ids = set()
self._counter = 0
self._positon = None
def handle_starttag(self, tag, attrs):
if tag == 'td':
@@ -142,27 +148,40 @@ class ProviderParser(HTMLParser):
self._current_cell = []
elif tag == 'tr':
row = self._current_row
# Satellite position
self._counter = self._counter + 1
if self._counter == 12:
pos = str(row)
pos = pos[pos.rfind("at") + 2:]
self._positon = "".join(c for c in pos if c.isalnum() or c == ".")
if len(row) == 12:
on_id, sep, tid = str(row[-2]).partition("-")
if tid and on_id not in self._ON_ID_BLACK_LIST and on_id not in self._ids:
row[-2] = on_id
self.rows.append(row)
self._ids.add(on_id)
row[0] = self._positon
self._current_row = []
def error(self, message):
pass
def reset(self):
super().reset()
self._counter = 0
def parse_providers(open_path):
parser = ProviderParser()
parser.reset()
with open(open_path, encoding="utf-8", errors="replace") as f:
parser = ProviderParser()
parser.reset()
parser.feed(f.read())
rows = parser.rows
if rows:
return [Provider(logo=r[2], name=r[5], url=r[6], on_id=r[-2], selected=True) for r in rows]
return [Provider(logo=r[2], name=r[5], pos=r[0], url=r[6], on_id=r[-2], selected=True) for r in rows]
if __name__ == "__main__":

View File

@@ -9,7 +9,7 @@
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">0.2.1 Pre-alpha</property>
<property name="version">0.2.3 Pre-alpha</property>
<property name="copyright" translatable="yes">2018 Dmitriy Yefremov
dmitry.v.yefremov@gmail.com
</property>
@@ -37,9 +37,6 @@ dmitry.v.yefremov@gmail.com
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
@@ -563,9 +560,6 @@ dmitry.v.yefremov@gmail.com
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<action-widgets>
@@ -611,7 +605,6 @@ dmitry.v.yefremov@gmail.com
<property name="value">1</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
<property name="page_size">1</property>
</object>
<object class="GtkDialog" id="settings_dialog">
<property name="can_focus">False</property>

View File

@@ -58,5 +58,16 @@ def show_dialog(dialog_type: DialogType, transient, text=None, options=None, act
return response
def get_chooser_dialog(transient, options, pattern, name):
file_filter = Gtk.FileFilter()
file_filter.add_pattern(pattern)
file_filter.set_name(name)
return show_dialog(dialog_type=DialogType.CHOOSER,
transient=transient,
options=options,
action_type=Gtk.FileChooserAction.OPEN,
file_filter=file_filter)
if __name__ == "__main__":
pass

View File

@@ -2,18 +2,20 @@ import os
from contextlib import suppress
from functools import lru_cache
import shutil
from app.commons import run_idle, log
from app.eparser import get_blacklist, write_blacklist, parse_m3u
from app.eparser import get_services, get_bouquets, write_bouquets, write_services, Bouquets, Bouquet, Service
from app.eparser.ecommons import CAS, FLAG
from app.eparser.enigma.bouquets import BqServiceType
from app.properties import get_config, write_config, Profile
from .picons_dialog import PiconsDialog
from . import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON
from .dialogs import show_dialog, DialogType
from .dialogs import show_dialog, DialogType, get_chooser_dialog
from .download_dialog import show_download_dialog
from .main_helper import edit_marker, insert_marker, move_items, edit, ViewTarget, set_flags, locate_in_services, \
scroll_to
scroll_to, get_base_model, update_picons, copy_picon_reference, assign_picon, remove_picon, search
from .picons_dialog import PiconsDialog
from .satellites_dialog import show_satellites_dialog
from .settings_dialog import show_settings_dialog
@@ -24,7 +26,7 @@ class MainAppWindow:
_BOUQUETS_LIST_NAME = "bouquets_tree_store"
# dynamically active elements depending on the selected view
_SERVICE_ELEMENTS = ("copy_tool_button", "to_fav_tool_button", "copy_menu_item", "services_to_fav_move_popup_item",
"services_edit_popup_item", "services_copy_popup_item")
"services_edit_popup_item", "services_copy_popup_item", "services_picon_popup_item")
_BOUQUET_ELEMENTS = ("edit_tool_button", "new_tool_button",
"bouquets_new_popup_item", "bouquets_edit_popup_item")
@@ -35,7 +37,7 @@ class MainAppWindow:
_FAV_ELEMENTS = ("cut_tool_button", "paste_tool_button", "cut_menu_item",
"paste_menu_item", "fav_cut_popup_item", "fav_paste_popup_item", "import_m3u_tool_button",
"fav_import_m3u_popup_item", "fav_insert_marker_popup_item", "fav_edit_popup_item",
"fav_locate_popup_item")
"fav_locate_popup_item", "fav_picon_popup_item")
_FAV_ONLY_ELEMENTS = ("import_m3u_tool_button", "fav_import_m3u_popup_item", "fav_insert_marker_popup_item",
"fav_edit_marker_popup_item")
@@ -51,7 +53,7 @@ class MainAppWindow:
"bouquets_remove_popup_item", "fav_remove_popup_item", "hide_tool_button",
"import_m3u_tool_button", "fav_import_m3u_popup_item", "fav_insert_marker_popup_item",
"fav_edit_marker_popup_item", "fav_edit_popup_item", "fav_locate_popup_item",
"services_copy_popup_item")
"services_copy_popup_item", "services_picon_popup_item", "fav_picon_popup_item")
def __init__(self):
handlers = {"on_close_main_window": self.on_quit,
@@ -90,16 +92,24 @@ class MainAppWindow:
"on_edit_marker": self.on_edit_marker,
"on_fav_popup": self.on_fav_popup,
"on_locate_in_services": self.on_locate_in_services,
"on_picons_loader_show": self.on_picons_loader_show}
"on_picons_loader_show": self.on_picons_loader_show,
"on_filter_changed": self.on_filter_changed,
"on_assign_picon": self.on_assign_picon,
"on_remove_picon": self.on_remove_picon,
"on_reference_picon": self.on_reference_picon,
"on_filter_toggled": self.on_filter_toggled,
"on_search_toggled": self.on_search_toggled,
"on_search": self.on_search}
self.__options = get_config()
self.__profile = self.__options.get("profile")
os.makedirs(os.path.dirname(self.__options.get(self.__profile).get("data_dir_path")), exist_ok=True)
# Used for copy/paste. When adding the previous data will not be deleted.
# Clearing only after the insertion!
self.__rows_buffer = []
self.__services = {}
self.__bouquets = {}
self.__bouquets_to_del = []
self.__picons = {}
self.__blacklist = set()
builder = Gtk.Builder()
@@ -122,6 +132,7 @@ class MainAppWindow:
self.__profile_label.set_text("Enigma2 v.4" if Profile(self.__profile) is Profile.ENIGMA_2 else "Neutrino-MP")
# dynamically active elements depending on the selected view
self.__tool_elements = {k: builder.get_object(k) for k in self.__DYNAMIC_ELEMENTS}
self.__picons_download_tool_button = builder.get_object("picons_download_tool_button")
self.__cas_label = builder.get_object("cas_label")
self.__fav_count_label = builder.get_object("fav_count_label")
self.__bouquets_count_label = builder.get_object("bouquets_count_label")
@@ -129,7 +140,18 @@ class MainAppWindow:
self.__radio_count_label = builder.get_object("radio_count_label")
self.__data_count_label = builder.get_object("data_count_label")
self.__fav_edit_marker_popup_item = builder.get_object("fav_edit_marker_popup_item")
self.__search_info_bar = builder.get_object("search_info_bar")
# Filter
self.__services_model_filter = builder.get_object("services_model_filter")
self.__services_model_filter.set_visible_func(self.services_filter_function)
self.__filter_entry = builder.get_object("filter_entry")
self.__filter_info_bar = builder.get_object("filter_info_bar")
self.init_drag_and_drop() # drag and drop
# Force ctrl press event for view. Multiple selections in lists only with Space key(as in file managers)!!!
self.__services_view.connect("key-press-event", self.force_ctrl)
self.__fav_view.connect("key-press-event", self.force_ctrl)
# Clipboard
self.__clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
self.__main_window.show()
def init_drag_and_drop(self):
@@ -146,6 +168,10 @@ class MainAppWindow:
self.__services_view.drag_source_set_target_list(None)
self.__services_view.drag_source_add_text_targets()
def force_ctrl(self, view, event):
""" Function for force ctrl press event for view """
event.state |= Gdk.ModifierType.CONTROL_MASK
def on_quit(self, *args):
""" Called before app quit """
write_config(self.__options) # storing current config
@@ -180,7 +206,7 @@ class MainAppWindow:
def on_copy(self, view):
model, paths = view.get_selection().get_selected_rows()
itrs = [model.get_iter(path) for path in paths]
rows = [(0, *model.get(in_itr, 2, 3, 4, 5, 7, 14, 16)) for in_itr in itrs]
rows = [(0, *model.get(in_itr, 2, 3, 4, 5, 7, 16, 18, 8)) for in_itr in itrs]
self.__rows_buffer.extend(rows)
def on_paste(self, view):
@@ -210,7 +236,8 @@ class MainAppWindow:
self.on_view_focus(view, None)
def on_edit(self, view):
name = view.get_model().get_name()
model = get_base_model(view.get_model())
name = model.get_name()
if name == self._BOUQUETS_LIST_NAME:
self.on_bouquets_edit(view)
# edit(view, self.__main_window, ViewTarget.BOUQUET)
@@ -228,36 +255,41 @@ class MainAppWindow:
if view.is_focus():
selection = view.get_selection()
model, paths = selection.get_selected_rows()
model_name = model.get_name()
model_name = get_base_model(model).get_name()
itrs = [model.get_iter(path) for path in paths]
rows = [model.get(in_itr, *[x for x in range(model.get_n_columns())]) for in_itr in itrs]
rows = [model[in_itr][:] for in_itr in itrs]
bq_selected = self.is_bouquet_selected()
fav_bouquet = None
if bq_selected:
fav_bouquet = self.__bouquets.get(bq_selected, None)
for itr in itrs:
if fav_bouquet and model_name == self._FAV_LIST_NAME:
del fav_bouquet[int(model.get_path(itr)[0])]
if model_name == self._BOUQUETS_LIST_NAME:
if len(model.get_path(itr)) < 2:
show_dialog(DialogType.ERROR, self.__main_window, "This item is not allowed to be removed!")
return
else:
self.delete_bouquet(bq_selected)
model.remove(itr)
if model_name == self._FAV_LIST_NAME:
self.update_fav_num_column(model)
self.remove_favs(fav_bouquet, itrs, model)
elif model_name == self._BOUQUETS_LIST_NAME:
self.delete_bouquets(itrs, model, bq_selected)
elif model_name == self._SERVICE_LIST_NAME:
self.delete_services(bq_selected, rows)
self.delete_services(bq_selected, itrs, model, rows)
self.on_view_focus(view, None)
return rows
def delete_services(self, bq_selected, rows):
def remove_favs(self, fav_bouquet, itrs, model):
""" Deleting bouquet services """
if fav_bouquet:
for itr in itrs:
del fav_bouquet[int(model.get_path(itr)[0])]
self.__fav_model.remove(itr)
self.update_fav_num_column(model)
def delete_services(self, bq_selected, itrs, model, rows):
""" Deleting services """
srv_itrs = [self.__services_model_filter.convert_iter_to_child_iter(
model.convert_iter_to_child_iter(itr)) for itr in itrs]
for s_itr in srv_itrs:
self.__services_model.remove(s_itr)
for row in rows:
# There are channels with the same parameters except for the name.
# None because it can have duplicates! Need fix
@@ -273,13 +305,16 @@ class MainAppWindow:
if bq_selected:
self.update_bouquet_channels(self.__fav_model, None, bq_selected)
def delete_bouquet(self, bouquet):
""" Deleting bouquet """
self.__bouquets.pop(bouquet)
self.__fav_model.clear()
profile = Profile(self.__profile)
if profile is Profile.ENIGMA_2:
self.__bouquets_to_del.append(self.get_bouquet_file_name(bouquet))
def delete_bouquets(self, itrs, model, bouquet):
""" Deleting bouquets """
for itr in itrs:
if len(model.get_path(itr)) < 2:
show_dialog(DialogType.ERROR, self.__main_window, "This item is not allowed to be removed!")
return
else:
self.__bouquets.pop(bouquet)
self.__fav_model.clear()
self.__bouquets_model.remove(itr)
def get_bouquet_file_name(self, bouquet):
bouquet_file_name = "{}userbouquet.{}.{}".format(self.__options.get(self.__profile).get("data_dir_path"),
@@ -292,7 +327,8 @@ class MainAppWindow:
if paths:
itr = model.get_iter(paths[0])
bq_type = model.get_value(itr, 1)
bq_type = model.get_value(itr, 3)
bq_name = "bouquet"
count = 0
key = "{}:{}".format(bq_name, bq_type)
@@ -340,14 +376,11 @@ class MainAppWindow:
itr = model.get_iter(paths[0])
bq_name, bq_type = model.get(itr, 0, 3)
response = show_dialog(DialogType.INPUT, self.__main_window, bq_name)
if response == Gtk.ResponseType.CANCEL:
return
model.set_value(itr, 0, response)
self.__bouquets["{}:{}".format(response, bq_type)] = self.__bouquets.pop("{}:{}".format(bq_name, bq_type))
if Profile(self.__profile) is Profile.ENIGMA_2:
self.__bouquets_to_del.append(self.get_bouquet_file_name(bq_selected))
def on_to_fav_move(self, view):
""" Move items from app to fav list """
@@ -359,6 +392,7 @@ class MainAppWindow:
def get_selection(self, view):
""" Creates a string from the iterators of the selected rows """
model, paths = view.get_selection().get_selected_rows()
model = get_base_model(model)
if len(paths) > 0:
itrs = [model.get_iter(path) for path in paths]
@@ -372,7 +406,7 @@ class MainAppWindow:
show_dialog(DialogType.ERROR, self.__main_window, "Error. No bouquet is selected!")
return
model = view.get_model()
model = get_base_model(view.get_model())
dest_index = 0
if drop_info:
@@ -390,22 +424,21 @@ class MainAppWindow:
if source == self._SERVICE_LIST_NAME:
ext_model = self.__services_view.get_model()
ext_itrs = [ext_model.get_iter_from_string(itr) for itr in itrs]
ext_rows = [ext_model.get(ext_itr, *[x for x in range(ext_model.get_n_columns())]) for
ext_itr in ext_itrs]
ext_rows = [ext_model[ext_itr][:] for ext_itr in ext_itrs]
dest_index -= 1
for ext_row in ext_rows:
dest_index += 1
fav_id = ext_row[-2]
channel = self.__services[fav_id]
model.insert(dest_index, (0, channel.coded, channel.service, channel.locked, channel.hide,
channel.service_type, channel.pos, channel.fav_id))
fav_bouquet.insert(dest_index, channel.fav_id)
fav_id = ext_row[18]
ch = self.__services[fav_id]
model.insert(dest_index, (0, ch.coded, ch.service, ch.locked, ch.hide,
ch.service_type, ch.pos, ch.fav_id, self.__picons.get(ch.picon_id, None)))
fav_bouquet.insert(dest_index, ch.fav_id)
elif source == self._FAV_LIST_NAME:
in_itrs = [model.get_iter_from_string(itr) for itr in itrs]
in_rows = [model.get(in_itr, *[x for x in range(model.get_n_columns())]) for in_itr in in_itrs]
in_rows = [model[in_itr][:] for in_itr in in_itrs]
for row in in_rows:
model.insert(dest_index, row)
fav_bouquet.insert(dest_index, row[4])
fav_bouquet.insert(dest_index, row[7])
for in_itr in in_itrs:
del fav_bouquet[int(model.get_path(in_itr)[0])]
model.remove(in_itr)
@@ -465,6 +498,8 @@ class MainAppWindow:
self.append_bouquets(data_path)
self.append_services(data_path)
self.update_services_counts(len(self.__services_model))
self.update_picons()
self.__picons_download_tool_button.set_sensitive(len(self.__services_model))
except FileNotFoundError as e:
show_dialog(DialogType.ERROR, self.__main_window, getattr(e, "message", str(e)) +
"\n\nPlease, download files from receiver or setup your path for read data!")
@@ -483,14 +518,14 @@ class MainAppWindow:
name, bt_type, locked, hidden = bt.name, bt.type, bt.locked, bt.hidden
self.__bouquets_model.append(parent, [name, locked, hidden, bt_type])
services = []
agr = [None] * 7
agr = [None] * 9
for srv in bt.services:
fav_id = srv.data
# IPTV and MARKER services
s_type = srv.type
if s_type is BqServiceType.MARKER or s_type is BqServiceType.IPTV:
self.__services[fav_id] = Service(*agr[0:3], srv.name, *agr[0:3],
s_type.name, *agr, srv.num, fav_id, None)
srv = Service(*agr[0:3], srv.name, *agr[0:3], s_type.name, *agr, srv.num, fav_id, None)
self.__services[fav_id] = srv
services.append(fav_id)
self.__bouquets["{}:{}".format(name, bt_type)] = services
@@ -517,29 +552,34 @@ class MainAppWindow:
self.__services.clear()
self.__rows_buffer.clear()
self.__bouquets.clear()
self.__bouquets_to_del.clear()
def on_data_save(self, *args):
if show_dialog(DialogType.QUESTION, self.__main_window) == Gtk.ResponseType.CANCEL:
return
path = self.__options.get(self.__profile).get("data_dir_path")
backup_path = path + "backup/"
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
# backup files in data dir(skipping dirs and satellites.xml)
for file in filter(lambda f: f != "satellites.xml" and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
shutil.move(os.path.join(path, file), backup_path + file)
bouquets = []
services_model = self.__services_view.get_model()
def parse_bouquets(model, b_path, itr):
bqs = None
if model.iter_has_child(itr):
num_of_children = model.iter_n_children(itr)
bqs = []
num_of_children = model.iter_n_children(itr)
for num in range(num_of_children):
bq_itr = model.iter_nth_child(itr, num)
bq_name, locked, hidden, bq_type = model.get(bq_itr, 0, 1, 2, 3)
favs = self.__bouquets["{}:{}".format(bq_name, bq_type)]
bq = Bouquet(bq_name, bq_type, [self.__services.get(f_id, None) for f_id in favs], locked, hidden)
bqs.append(bq)
bqs = Bouquets(*model.get(itr, 0, 3), bqs)
bouquets.append(bqs)
if len(b_path) == 1:
bouquets.append(Bouquets(*model.get(itr, 0, 3), bqs if bqs else []))
profile = Profile(self.__profile)
# Getting bouquets
@@ -549,11 +589,7 @@ class MainAppWindow:
services = [Service(*row[:]) for row in services_model]
write_services(path, services, profile)
# removing bouquet files
if profile is profile.ENIGMA_2:
for bqf in self.__bouquets_to_del:
with suppress(FileNotFoundError):
os.remove(bqf)
self.__bouquets_to_del.clear()
if profile is Profile.ENIGMA_2:
# blacklist
write_blacklist(path, self.__blacklist)
@@ -597,7 +633,8 @@ class MainAppWindow:
channel = self.__services.get(ch_id, None)
if channel:
self.__fav_model.append((num + 1, channel.coded, channel.service, channel.locked,
channel.hide, channel.service_type, channel.pos, channel.fav_id))
channel.hide, channel.service_type, channel.pos, channel.fav_id,
self.__picons.get(channel.picon_id, None)))
def is_bouquet_selected(self):
""" Checks whether the bouquet is selected
@@ -622,19 +659,21 @@ class MainAppWindow:
response = show_settings_dialog(self.__main_window, self.__options)
if response != Gtk.ResponseType.CANCEL:
profile = self.__options.get("profile")
self.__status_bar.push(0, "Current IP: " + self.__options.get(profile).get("host"))
if profile != self.__profile:
self.__status_bar.push(0, "Current IP: " + self.__options.get(profile).get("host"))
self.__profile_label.set_text("Enigma 2 v.4" if Profile(profile) is Profile.ENIGMA_2 else "Neutrino-MP")
self.__profile = profile
self.clear_current_data()
self.update_services_counts()
self.__picons_download_tool_button.set_sensitive(len(self.__services_model))
def on_tree_view_key_release(self, view, event):
""" Handling keystrokes """
key = event.keyval
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
alt = event.state & Gdk.ModifierType.MOD1_MASK
model_name = view.get_model().get_name()
model = get_base_model(view.get_model())
model_name = model.get_name()
if key == Gdk.KEY_Delete:
self.on_delete(view)
@@ -643,7 +682,7 @@ class MainAppWindow:
elif ctrl and key in (Gdk.KEY_Down, Gdk.KEY_Page_Down, Gdk.KEY_KP_Page_Down):
self.move_items(key)
elif model_name == self._FAV_LIST_NAME and key == Gdk.KEY_Control_L or key == Gdk.KEY_Control_R:
self.update_fav_num_column(view.get_model())
self.update_fav_num_column(model)
self.update_bouquet_list()
elif key == Gdk.KEY_Insert:
# Move items from app to fav list
@@ -666,8 +705,8 @@ class MainAppWindow:
self.on_hide(None)
elif ctrl and key == Gdk.KEY_E or key == Gdk.KEY_e or key == Gdk.KEY_F2:
self.on_edit(view)
elif key == Gdk.KEY_space and model_name == self._FAV_LIST_NAME:
pass
elif key == Gdk.KEY_Left or key == Gdk.KEY_Right:
view.do_unselect_all(view)
def on_download(self, item):
show_download_dialog(transient=self.__main_window,
@@ -678,7 +717,7 @@ class MainAppWindow:
@run_idle
def on_view_focus(self, view, focus_event):
profile = Profile(self.__profile)
model = view.get_model()
model = get_base_model(view.get_model())
model_name = model.get_name()
not_empty = len(model) > 0 # if > 0 model has items
@@ -764,14 +803,7 @@ class MainAppWindow:
def on_import_m3u(self, item):
""" Imports iptv from m3u files. """
file_filter = Gtk.FileFilter()
file_filter.add_pattern("*.m3u")
file_filter.set_name("m3u files")
response = show_dialog(dialog_type=DialogType.CHOOSER,
transient=self.__main_window,
options=self.__options.get(self.__profile),
action_type=Gtk.FileChooserAction.OPEN,
file_filter=file_filter)
response = get_chooser_dialog(self.__main_window, self.__options.get(self.__profile), "*.m3u", "m3u files")
if response == Gtk.ResponseType.CANCEL:
return
@@ -806,9 +838,69 @@ class MainAppWindow:
def on_locate_in_services(self, view):
locate_in_services(view, self.__services_view, self.__main_window)
@run_idle
def on_picons_loader_show(self, item):
dialog = PiconsDialog(self.__main_window, self.__options.get(self.__profile), Profile(self.__profile))
ids = {}
if Profile(self.__profile) is Profile.ENIGMA_2:
for r in self.__services_model:
data = r[9].split("_")
ids["{}:{}:{}".format(data[3], data[5], data[6])] = r[9]
dialog = PiconsDialog(self.__main_window, self.__options.get(self.__profile), ids, Profile(self.__profile))
dialog.show()
self.update_picons()
@run_idle
def on_filter_toggled(self, toggle_button: Gtk.ToggleToolButton):
self.__filter_info_bar.set_visible(toggle_button.get_active())
@run_idle
def on_filter_changed(self, entry):
self.__services_model_filter.refilter()
def services_filter_function(self, model, iter, data):
if self.__services_model_filter is None or self.__services_model_filter == "None":
return True
else:
return self.__filter_entry.get_text() in str(model.get(iter, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16))
def on_search_toggled(self, toggle_button: Gtk.ToggleToolButton):
self.__search_info_bar.set_visible(toggle_button.get_active())
@run_idle
def on_search(self, entry, event):
search(entry.get_text(),
self.__services_view,
self.__fav_view,
self.__bouquets_view,
self.__services,
self.__bouquets)
@run_idle
def update_picons(self):
update_picons(self.__options.get(self.__profile).get("picons_dir_path"), self.__picons, self.__services_model)
def on_assign_picon(self, view):
assign_picon(self.get_target_view(view),
self.__services_view,
self.__fav_view,
self.__main_window,
self.__picons,
self.__options.get(self.__profile),
self.__services)
def on_remove_picon(self, view):
remove_picon(self.get_target_view(view),
self.__services_view,
self.__fav_view, self.__picons,
self.__options.get(self.__profile))
def on_reference_picon(self, view):
""" Copying picon id to clipboard """
copy_picon_reference(self.get_target_view(view), view, self.__services, self.__clipboard, self.__main_window)
def get_target_view(self, view):
return ViewTarget.SERVICES if Gtk.Buildable.get_name(view) == "services_tree_view" else ViewTarget.FAV
def start_app():

View File

@@ -1,11 +1,16 @@
""" This is helper module for ui """
from enum import Enum
import os
import shutil
from gi.repository import GdkPixbuf
from app.eparser import Service
from app.eparser.ecommons import FLAG
from app.eparser.enigma.bouquets import BqServiceType, to_bouquet_id
from . import Gtk, Gdk, HIDE_ICON, LOCKED_ICON
from .dialogs import show_dialog, DialogType
from .dialogs import show_dialog, DialogType, get_chooser_dialog
class ViewTarget(Enum):
@@ -28,15 +33,16 @@ def insert_marker(view, bouquets, selected_bouquet, channels, parent_window):
return
# Searching for max num value in all marker services (if empty default = 0)
max_num = max(map(lambda num: int(num.data_id, 16),
max_num = max(map(lambda num: int(num.data_id, 18),
filter(lambda ch: ch.service_type == BqServiceType.MARKER.name, channels.values())), default=0)
max_num = '{:x}'.format(max_num + 1)
fav_id = "1:64:{}:0:0:0:0:0:0:0::{}\n#DESCRIPTION {}\n".format(max_num, response, response)
s_type = BqServiceType.MARKER.name
model, paths = view.get_selection().get_selected_rows()
itr = model.insert_before(model.get_iter(paths[0]), (None, None, response, None, None, s_type, None, fav_id))
channels[fav_id] = Service(None, None, None, response, None, None, None, s_type, *[None] * 7, max_num, fav_id, None)
marker = (None, None, response, None, None, s_type, None, fav_id, None)
itr = model.insert_before(model.get_iter(paths[0]), marker) if paths else model.insert(0, marker)
bouquets[selected_bouquet].insert(model.get_path(itr)[0], fav_id)
channels[fav_id] = Service(None, None, None, response, None, None, None, s_type, *[None] * 9, max_num, fav_id, None)
def edit_marker(view, bouquets, selected_bouquet, channels, parent_window):
@@ -53,7 +59,7 @@ def edit_marker(view, bouquets, selected_bouquet, channels, parent_window):
old_ch = channels.pop(fav_id, None)
new_fav_id = "{}::{}\n#DESCRIPTION {}\n".format(fav_id.split("::")[0], response, response)
model.set(itr, {2: response, 7: new_fav_id})
channels[new_fav_id] = Service(*old_ch[0:3], response, *old_ch[4:15], old_ch.data_id, new_fav_id, None)
channels[new_fav_id] = Service(*old_ch[0:3], response, *old_ch[4:17], old_ch.data_id, new_fav_id, None)
bq_services.pop(index)
bq_services.insert(index, new_fav_id)
@@ -94,6 +100,7 @@ def move_items(key, view):
def edit(view, parent_window, target, fav_view=None, service_view=None, channels=None):
model, paths = view.get_selection().get_selected_rows()
model = get_base_model(model)
if not paths:
return
@@ -106,7 +113,7 @@ def edit(view, parent_window, target, fav_view=None, service_view=None, channels
channel_name = None
if target is ViewTarget.SERVICES:
name, fav_id = model.get(itr, 3, 16)
name, fav_id = model.get(itr, 3, 18)
f_id = fav_id
response = show_dialog(DialogType.INPUT, parent_window, name)
if response == Gtk.ResponseType.CANCEL:
@@ -129,8 +136,8 @@ def edit(view, parent_window, target, fav_view=None, service_view=None, channels
model.set_value(itr, 2, response)
if service_view is not None:
for row in service_view.get_model():
if row[16] == fav_id:
for row in get_base_model(service_view.get_model()):
if row[18] == fav_id:
row[3] = response
break
@@ -157,16 +164,18 @@ def set_flags(flag, services_view, fav_view, channels, blacklist):
if not paths:
return
model = get_base_model(model)
if flag is FLAG.HIDE:
if target is ViewTarget.SERVICES:
set_hide(channels, model, paths)
else:
fav_ids = [model.get_value(model.get_iter(path), 7) for path in paths]
srv_model = services_view.get_model()
srv_paths = [row.path for row in srv_model if row[16] in fav_ids]
srv_model = get_base_model(services_view.get_model())
srv_paths = [row.path for row in srv_model if row[18] in fav_ids]
set_hide(channels, srv_model, srv_paths)
elif flag is FLAG.LOCK:
set_lock(blacklist, channels, model, paths, target, services_model=services_view.get_model())
set_lock(blacklist, channels, model, paths, target, services_model=get_base_model(services_view.get_model()))
return True
@@ -179,10 +188,12 @@ def set_lock(blacklist, channels, model, paths, target, services_model):
for path in paths:
itr = model.get_iter(path)
fav_id = model.get_value(itr, 16 if target is ViewTarget.SERVICES else 7)
fav_id = model.get_value(itr, 18 if target is ViewTarget.SERVICES else 7)
channel = channels.get(fav_id, None)
if channel:
bq_id = to_bouquet_id(channel)
if not bq_id:
continue
blacklist.discard(bq_id) if locked else blacklist.add(bq_id)
model.set_value(itr, col_num, None if locked else LOCKED_ICON)
channels[fav_id] = Service(*channel[:4], None if locked else LOCKED_ICON, *channel[5:])
@@ -190,7 +201,7 @@ def set_lock(blacklist, channels, model, paths, target, services_model):
if target is ViewTarget.FAV and ids:
for ch in services_model:
if ch[16] in ids:
if ch[18] in ids:
ch[4] = None if locked else LOCKED_ICON
@@ -230,7 +241,7 @@ def set_hide(channels, model, paths):
flags.append(value)
model.set_value(itr, 0, (",".join(reversed(sorted(flags)))))
fav_id = model.get_value(itr, 16)
fav_id = model.get_value(itr, 18)
channel = channels.get(fav_id, None)
if channel:
channels[fav_id] = Service(*channel[:5], None if hide else HIDE_ICON, *channel[6:])
@@ -257,7 +268,7 @@ def locate_in_services(fav_view, services_view, parent_window):
fav_id = model.get_value(model.get_iter(paths[0]), 7)
for index, row in enumerate(services_view.get_model()):
if row[16] == fav_id:
if row[18] == fav_id:
scroll_to(index, services_view)
break
@@ -272,8 +283,158 @@ def scroll_to(index, view, paths=None):
selection.select_path(index)
# ***************** Picons *********************#
def update_picons(path, picons, model):
if not os.path.exists(path):
return
for file in os.listdir(path):
picons[file] = get_picon_pixbuf(path + file)
for r in model:
model.set_value(model.get_iter(r.path), 8, picons.get(r[9], None))
def assign_picon(target, srv_view, fav_view, transient, picons, options, services):
view = srv_view if target is ViewTarget.SERVICES else fav_view
model, paths = view.get_selection().get_selected_rows()
if not is_only_one_item_selected(paths, transient):
return
response = get_chooser_dialog(transient, options, "*.png", "png files")
if response == Gtk.ResponseType.CANCEL:
return
if not str(response).endswith(".png"):
show_dialog(DialogType.ERROR, transient, text="No png file is selected!")
return
picon_pos = 8
model = get_base_model(model)
itr = model.get_iter(paths)
fav_id = model.get_value(itr, 18 if target is ViewTarget.SERVICES else 7)
picon_id = services.get(fav_id)[9]
if picon_id:
picon_file = options.get("picons_dir_path") + picon_id
if os.path.isfile(response):
shutil.copy(response, picon_file)
picon = get_picon_pixbuf(picon_file)
picons[picon_id] = picon
model.set_value(itr, picon_pos, picon)
if target is ViewTarget.SERVICES:
set_picon(fav_id, fav_view.get_model(), picon, 7, picon_pos)
else:
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, 18, picon_pos)
def set_picon(fav_id, model, picon, fav_id_pos, picon_pos):
for row in model:
if row[fav_id_pos] == fav_id:
row[picon_pos] = picon
break
def remove_picon(target, srv_view, fav_view, picons, options):
view = srv_view if target is ViewTarget.SERVICES else fav_view
model, paths = view.get_selection().get_selected_rows()
model = get_base_model(model)
fav_ids = []
picon_ids = []
picon_pos = 8 # picon position is equal for services and fav
for path in paths:
itr = model.get_iter(path)
model.set_value(itr, picon_pos, None)
if target is ViewTarget.SERVICES:
fav_ids.append(model.get_value(itr, 18))
picon_ids.append(model.get_value(itr, 9))
else:
fav_ids.append(model.get_value(itr, 7))
def remove(md, path, itr):
if md.get_value(itr, 7 if target is ViewTarget.SERVICES else 18) in fav_ids:
md.set_value(itr, picon_pos, None)
if target is ViewTarget.FAV:
picon_ids.append(md.get_value(itr, 9))
fav_view.get_model().foreach(remove) if target is ViewTarget.SERVICES else get_base_model(
srv_view.get_model()).foreach(remove)
pions_path = options.get("picons_dir_path")
backup_path = options.get("data_dir_path") + "backup/picons/"
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
for p_id in picon_ids:
picons[p_id] = None
src = pions_path + p_id
if os.path.isfile(src):
shutil.move(src, backup_path + p_id)
def copy_picon_reference(target, view, services, clipboard, transient):
""" Copying picon id to clipboard """
model, paths = view.get_selection().get_selected_rows()
if not is_only_one_item_selected(paths, transient):
return
if target is ViewTarget.SERVICES:
picon_id = model.get_value(model.get_iter(paths), 9)
if picon_id:
clipboard.set_text(picon_id.rstrip(".png"), -1)
else:
show_dialog(DialogType.ERROR, transient, "No reference is present!")
elif target is ViewTarget.FAV:
fav_id = model.get_value(model.get_iter(paths), 7)
srv = services.get(fav_id, None)
if srv and srv.picon_id:
clipboard.set_text(srv.picon_id.rstrip(".png"), -1)
else:
show_dialog(DialogType.ERROR, transient, "No reference is present!")
def is_only_one_item_selected(paths, transient):
if len(paths) > 1:
show_dialog(DialogType.ERROR, transient, "Please, select only one item!")
return False
if not paths:
show_dialog(DialogType.ERROR, transient, "No selected item!")
return False
return True
def get_picon_pixbuf(path):
return GdkPixbuf.Pixbuf.new_from_file_at_scale(filename=path, width=32, height=32, preserve_aspect_ratio=True)
# ***************** Search *********************#
def search(text, srv_view, fav_view, bqs_view, services, bouquets):
for view in srv_view, fav_view:
model = get_base_model(view.get_model())
selection = view.get_selection()
selection.unselect_all()
if not text:
continue
paths = []
text = text.upper()
for r in model:
if text in str(r[:]).upper():
path = r.path
selection.select_path(r.path)
paths.append(path)
if paths:
view.scroll_to_cell(paths[0], None)
# ***************** Others *********************#
def update_entry_data(entry, dialog, options):
""" Updates value in text entry from chooser dialog """
response = show_dialog(dialog_type=DialogType.CHOOSER, transient=dialog, options=options)
@@ -283,5 +444,12 @@ def update_entry_data(entry, dialog, options):
return False
def get_base_model(model):
""" Returns base tree model if has wrappers ("TreeModelSort" and "TreeModelFilter") """
if type(model) is Gtk.TreeModelSort:
return model.get_model().get_model()
return model
if __name__ == "__main__":
pass

View File

@@ -71,6 +71,8 @@
<column type="gchararray"/>
<!-- column-name fav_id -->
<column type="gchararray"/>
<!-- column-name picon -->
<column type="GdkPixbuf"/>
</columns>
<signal name="row-deleted" handler="on_model_changed" swapped="no"/>
<signal name="row-inserted" handler="on_model_changed" swapped="no"/>
@@ -80,6 +82,41 @@
<property name="can_focus">False</property>
<property name="icon_name">emblem-downloads</property>
</object>
<object class="GtkImage" id="image10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-copy</property>
</object>
<object class="GtkImage" id="image11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">insert-link</property>
</object>
<object class="GtkImage" id="image12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-clear</property>
</object>
<object class="GtkImage" id="image13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">insert-image</property>
</object>
<object class="GtkImage" id="image14">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">insert-link</property>
</object>
<object class="GtkImage" id="image15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-clear</property>
</object>
<object class="GtkImage" id="image16">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-copy</property>
</object>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -207,6 +244,64 @@
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_picon_popup_item">
<property name="label" translatable="yes">Picon</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">image13</property>
<property name="use_stock">False</property>
<child type="submenu">
<object class="GtkMenu" id="fav_picon_popoup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="fav_assign_picon_popup_item">
<property name="label" translatable="yes">Assign</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image14</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_picon" object="fav_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_remove_picon_popup_item">
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image15</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_remove_picon" object="fav_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="fav_pupup_separator_5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_reference_picon_popup_item">
<property name="label" translatable="yes">Copy reference</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image16</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_reference_picon" object="fav_tree_view" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="fav_pupup_separator_4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_remove_popup_item">
<property name="label">gtk-remove</property>
@@ -224,10 +319,134 @@
<property name="can_focus">False</property>
<property name="icon_name">insert-image</property>
</object>
<object class="GtkImage" id="image9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">insert-image</property>
</object>
<object class="GtkMenu" id="services_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_to_fav_move_popup_item">
<property name="label">gtk-go-forward</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_move" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_copy_popup_item">
<property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_copy" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_edit_popup_item">
<property name="label">gtk-edit</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="resize_mode">immediate</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_picon_popup_item">
<property name="label" translatable="yes">Picon</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">image9</property>
<property name="use_stock">False</property>
<child type="submenu">
<object class="GtkMenu" id="services_picon_popoup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_assign_picon_popup_item">
<property name="label">Assign</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image11</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_picon_popup_item">
<property name="label">Remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image12</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_remove_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem6">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_reference_picon_popup_item">
<property name="label" translatable="yes">Copy reference</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image10</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_reference_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_popup_item">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_delete" swapped="no"/>
</object>
</child>
</object>
<object class="GtkImage" id="send_recive_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">mail-send-receive</property>
<property name="icon_name">network-transmit-receive</property>
</object>
<object class="GtkListStore" id="services_list_store">
<columns>
@@ -247,6 +466,10 @@
<column type="gchararray"/>
<!-- column-name service_type -->
<column type="gchararray"/>
<!-- column-name picon -->
<column type="GdkPixbuf"/>
<!-- column-name picon_id -->
<column type="gchararray"/>
<!-- column-name ssid -->
<column type="gchararray"/>
<!-- column-name freq -->
@@ -270,6 +493,12 @@
</columns>
<signal name="row-deleted" handler="on_model_changed" swapped="no"/>
</object>
<object class="GtkTreeModelFilter" id="services_model_filter">
<property name="child_model">services_list_store</property>
</object>
<object class="GtkTreeModelSort" id="services_model_tree_model_sort">
<property name="model">services_model_filter</property>
</object>
<object class="GtkApplicationWindow" id="main_window">
<property name="width_request">640</property>
<property name="can_focus">False</property>
@@ -514,7 +743,7 @@
<property name="tooltip_text" translatable="yes">FTP-transfer</property>
<property name="label" translatable="yes">Download</property>
<property name="use_underline">True</property>
<property name="icon_name">mail-send-receive</property>
<property name="icon_name">network-transmit-receive</property>
<signal name="clicked" handler="on_download" swapped="no"/>
</object>
<packing>
@@ -547,6 +776,46 @@
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem8">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton" id="filter_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Services filter</property>
<property name="label" translatable="yes">Services filter</property>
<property name="use_underline">True</property>
<property name="icon_name">tools-check-spelling</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton" id="search_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Global search</property>
<property name="label" translatable="yes">Search</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-find</property>
<signal name="toggled" handler="on_search_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="toolbutton4">
<property name="visible">True</property>
@@ -821,6 +1090,7 @@
<child>
<object class="GtkToolButton" id="picons_download_tool_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Picons</property>
<property name="label" translatable="yes">Picons loader</property>
@@ -884,6 +1154,98 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="search_info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="search_infobar_action_area">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="search_infobar_content_area">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="width_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<signal name="key-release-event" handler="on_search" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator5">
<property name="visible">True</property>
@@ -893,7 +1255,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
@@ -901,8 +1263,8 @@
<property name="height_request">250</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="box4">
@@ -925,12 +1287,13 @@
<object class="GtkScrolledWindow" id="services_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="services_tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">services_list_store</property>
<property name="model">services_model_tree_model_sort</property>
<property name="search_column">3</property>
<property name="rubber_banding">True</property>
<property name="enable_grid_lines">both</property>
@@ -973,6 +1336,7 @@
<object class="GtkTreeViewColumn" id="service_column">
<property name="resizable">True</property>
<property name="spacing">2</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Service</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1006,7 +1370,7 @@
<child>
<object class="GtkTreeViewColumn" id="package_column">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Package</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1022,6 +1386,7 @@
<child>
<object class="GtkTreeViewColumn" id="service_type_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Type</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1037,33 +1402,25 @@
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="ssid_column">
<property name="resizable">True</property>
<property name="title" translatable="yes">Ssid</property>
<property name="expand">True</property>
<object class="GtkTreeViewColumn" id="picon_column">
<property name="title" translatable="yes">Picon</property>
<property name="reorderable">True</property>
<property name="sort_column_id">8</property>
<property name="sort_column_id">9</property>
<child>
<object class="GtkCellRendererText" id="ssid_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<object class="GtkCellRendererPixbuf" id="picon_cellrendererpixbuf"/>
<attributes>
<attribute name="text">8</attribute>
<attribute name="pixbuf">8</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="freq_column">
<property name="resizable">True</property>
<property name="title" translatable="yes">Freq</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">9</property>
<object class="GtkTreeViewColumn" id="picon_id_column">
<property name="visible">False</property>
<property name="sizing">fixed</property>
<property name="title" translatable="yes">Picon ID</property>
<child>
<object class="GtkCellRendererText" id="freq_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<object class="GtkCellRendererText" id="picon_id_cellrenderertext"/>
<attributes>
<attribute name="text">9</attribute>
</attributes>
@@ -1071,14 +1428,15 @@
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="rate_column">
<object class="GtkTreeViewColumn" id="ssid_column">
<property name="resizable">True</property>
<property name="title" translatable="yes">Rate</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Ssid</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">10</property>
<child>
<object class="GtkCellRendererText" id="rate_cellrenderertext">
<object class="GtkCellRendererText" id="ssid_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
@@ -1088,14 +1446,15 @@
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="pol_column">
<object class="GtkTreeViewColumn" id="freq_column">
<property name="resizable">True</property>
<property name="title" translatable="yes">Pol</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Freq</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">11</property>
<child>
<object class="GtkCellRendererText" id="pol_cellrenderertext">
<object class="GtkCellRendererText" id="freq_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
@@ -1105,14 +1464,15 @@
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fec_column">
<object class="GtkTreeViewColumn" id="rate_column">
<property name="resizable">True</property>
<property name="title" translatable="yes">FEC</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Rate</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">12</property>
<child>
<object class="GtkCellRendererText" id="fec_cellrenderertext">
<object class="GtkCellRendererText" id="rate_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
@@ -1122,14 +1482,15 @@
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="system_column">
<object class="GtkTreeViewColumn" id="pol_column">
<property name="resizable">True</property>
<property name="title" translatable="yes">System</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Pol</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">13</property>
<child>
<object class="GtkCellRendererText" id="system_cellrenderertex">
<object class="GtkCellRendererText" id="pol_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
@@ -1138,18 +1499,55 @@
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fec_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">FEC</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">14</property>
<child>
<object class="GtkCellRendererText" id="fec_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
<attribute name="text">14</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="system_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">System</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">15</property>
<child>
<object class="GtkCellRendererText" id="system_cellrenderertex">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
<attribute name="text">15</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="pos_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Pos</property>
<property name="expand">True</property>
<property name="sort_column_id">14</property>
<property name="sort_column_id">16</property>
<child>
<object class="GtkCellRendererText" id="pos_cellrenderertext1">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
<attribute name="text">14</attribute>
<attribute name="text">16</attribute>
</attributes>
</child>
</object>
@@ -1161,7 +1559,7 @@
<child>
<object class="GtkCellRendererText" id="data_id_cellrenderertext"/>
<attributes>
<attribute name="text">15</attribute>
<attribute name="text">17</attribute>
</attributes>
</child>
</object>
@@ -1173,7 +1571,7 @@
<child>
<object class="GtkCellRendererText" id="fav_id_cellrenderertext"/>
<attributes>
<attribute name="text">16</attribute>
<attribute name="text">18</attribute>
</attributes>
</child>
</object>
@@ -1185,7 +1583,7 @@
<child>
<object class="GtkCellRendererText" id="transponder_cellrenderertext"/>
<attributes>
<attribute name="text">17</attribute>
<attribute name="text">19</attribute>
</attributes>
</child>
</object>
@@ -1199,9 +1597,78 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="filter_info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="filter_infobar_action_area">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="filter_infobar_content_area">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkSearchEntry" id="filter_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">tools-check-spelling</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<signal name="search-changed" handler="on_filter_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="services_bar_box">
<property name="height_request">25</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="resize_mode">queue</property>
@@ -1224,12 +1691,14 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">CAS</property>
<property name="width_chars">10</property>
<property name="width_chars">20</property>
<property name="max_width_chars">20</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
@@ -1323,11 +1792,24 @@
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">9</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
</object>
@@ -1362,6 +1844,7 @@
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="fav_tree_view">
@@ -1405,6 +1888,12 @@
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Service</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererPixbuf" id="fav_picon_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">8</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_coded_cellrendererpixbuf"/>
<attributes>
@@ -1482,7 +1971,7 @@
</child>
<child>
<object class="GtkBox" id="fav_bar_box">
<property name="height_request">25</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
@@ -1503,7 +1992,8 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">0</property>
<property name="width_chars">10</property>
<property name="width_chars">15</property>
<property name="max_width_chars">15</property>
<property name="xalign">0</property>
</object>
<packing>
@@ -1549,6 +2039,7 @@
<object class="GtkScrolledWindow" id="scrolledwindow3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="bouquets_tree_view">
@@ -1619,7 +2110,7 @@
</child>
<child>
<object class="GtkBox" id="bouquet_bar_box">
<property name="height_request">25</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
@@ -1640,7 +2131,8 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">0</property>
<property name="width_chars">5</property>
<property name="width_chars">10</property>
<property name="max_width_chars">10</property>
<property name="xalign">0</property>
</object>
<packing>
@@ -1676,7 +2168,7 @@
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">1</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
<child>
@@ -1689,7 +2181,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">4</property>
<property name="position">5</property>
</packing>
</child>
<child>
@@ -1698,8 +2190,6 @@
<property name="can_focus">False</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="spacing">2</property>
<property name="homogeneous">True</property>
<child>
@@ -1742,7 +2232,7 @@
<object class="GtkLabel" id="ver_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Ver. 0.2.1 Pre-alpha</property>
<property name="label" translatable="yes">Ver. 0.2.3 Pre-alpha</property>
<property name="xalign">0.94999998807907104</property>
</object>
<packing>
@@ -1755,71 +2245,10 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
<property name="position">7</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkMenu" id="services_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_to_fav_move_popup_item">
<property name="label">gtk-go-forward</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_move" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_copy_popup_item">
<property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_copy" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_edit_popup_item">
<property name="label">gtk-edit</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="resize_mode">immediate</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_popup_item">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_delete" swapped="no"/>
</object>
</child>
</object>
</interface>

View File

@@ -9,6 +9,8 @@
<column type="GdkPixbuf"/>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name pos -->
<column type="gchararray"/>
<!-- column-name url -->
<column type="gchararray"/>
<!-- column-name on_id -->
@@ -153,55 +155,175 @@
</packing>
</child>
<child>
<object class="GtkBox" id="format_box">
<object class="GtkGrid" id="format_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="label1">
<object class="GtkBox" id="name_format_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Picons name format:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">5</property>
<child>
<object class="GtkRadioButton" id="enigma2_radio_button">
<property name="label" translatable="yes">Enigma2 (default)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_mp_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="neutrino_mp_radio_button">
<property name="label" translatable="yes">Neutrino-MP</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma2_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="resize_format_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Resize: </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="resize_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkRadioButton" id="resize_no_radio_button">
<property name="label" translatable="yes">No(default)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_100_60_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="resize_220_132_radio_button">
<property name="label" translatable="yes">220x132</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_100_60_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="resize_100_60_radio_button">
<property name="label" translatable="yes">100x60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_no_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="label" translatable="yes">Picons name format:</property>
<property name="margin_right">5</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="enigma2_radio_button">
<property name="label" translatable="yes">Enigma2 (default)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_mp_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="neutrino_mp_radio_button">
<property name="label" translatable="yes">Neutrino-MP</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma2_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<style>
@@ -210,7 +332,7 @@
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
@@ -231,6 +353,9 @@
<property name="can_focus">False</property>
<property name="label" translatable="yes">Satellite url (www.lyngsat.com):</property>
<property name="xalign">0.019999999552965164</property>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
@@ -289,14 +414,30 @@
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="pos_column">
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Position</property>
<child>
<object class="GtkCellRendererText" id="pos_cellrenderertext1">
<property name="xalign">0.50999999046325684</property>
<property name="editable">True</property>
<signal name="edited" handler="on_position_edited" swapped="no"/>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="url_column">
<property name="visible">False</property>
<property name="title" translatable="yes">Url</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<object class="GtkCellRendererText" id="url_cellrenderertext"/>
<attributes>
<attribute name="text">2</attribute>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
@@ -306,9 +447,9 @@
<property name="visible">False</property>
<property name="title" translatable="yes">ONID</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<object class="GtkCellRendererText" id="onid_cellrenderertext"/>
<attributes>
<attribute name="text">3</attribute>
<attribute name="text">4</attribute>
</attributes>
</child>
</object>
@@ -321,7 +462,7 @@
<signal name="toggled" handler="on_selected_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="active">4</attribute>
<attribute name="active">5</attribute>
</attributes>
</child>
</object>
@@ -332,7 +473,7 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">7</property>
<property name="position">10</property>
</packing>
</child>
<child>
@@ -344,7 +485,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">10</property>
<property name="position">11</property>
</packing>
</child>
<child>
@@ -442,7 +583,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">11</property>
<property name="position">12</property>
</packing>
</child>
<child>
@@ -479,7 +620,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">12</property>
<property name="position">13</property>
</packing>
</child>
<child>
@@ -545,7 +686,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">13</property>
<property name="position">14</property>
</packing>
</child>
<child>
@@ -556,7 +697,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">14</property>
<property name="position">15</property>
</packing>
</child>
</object>
@@ -569,4 +710,10 @@
</object>
</child>
</object>
<object class="GtkListStore" id="sat_position_list_store">
<columns>
<!-- column-name pos -->
<column type="gchararray"/>
</columns>
</object>
</interface>

View File

@@ -15,7 +15,8 @@ from .main_helper import update_entry_data
class PiconsDialog:
def __init__(self, transient, options, profile=Profile.ENIGMA_2):
def __init__(self, transient, options, picon_ids, profile=Profile.ENIGMA_2):
self._picon_ids = picon_ids
self._TMP_DIR = tempfile.gettempdir() + "/"
self._BASE_URL = "www.lyngsat.com/packages/"
self._PATTERN = re.compile("^https://www\.lyngsat\.com/[\w-]+\.html$")
@@ -31,7 +32,8 @@ class PiconsDialog:
"on_info_bar_close": self.on_info_bar_close,
"on_picons_dir_open": self.on_picons_dir_open,
"on_selected_toggled": self.on_selected_toggled,
"on_url_changed": self.on_url_changed}
"on_url_changed": self.on_url_changed,
"on_position_edited": self.on_position_edited}
builder = Gtk.Builder()
builder.add_objects_from_file(UI_RESOURCES_PATH + "picons_dialog.glade",
@@ -54,6 +56,9 @@ class PiconsDialog:
self._receive_tool_button = builder.get_object("receive_tool_button")
self._enigma2_radio_button = builder.get_object("enigma2_radio_button")
self._neutrino_mp_radio_button = builder.get_object("neutrino_mp_radio_button")
self._resize_no_radio_button = builder.get_object("resize_no_radio_button")
self._resize_220_132_radio_button = builder.get_object("resize_220_132_radio_button")
self._resize_100_60_radio_button = builder.get_object("resize_100_60_radio_button")
# style
self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
@@ -90,8 +95,7 @@ class PiconsDialog:
providers = parse_providers(self._TMP_DIR + url[url.find("w"):])
if providers:
for p in providers:
logo = self.get_pixbuf(p[0])
model.append((logo, p.name, p.url, p.on_id, p.selected))
model.append((self.get_pixbuf(p[0]), p.name, p.pos, p.url, p.on_id, p.selected))
self.update_receive_button_state()
def get_pixbuf(self, img_url):
@@ -116,8 +120,8 @@ class PiconsDialog:
break
self.process_provider(Provider(*prv))
def process_provider(self, provider):
url = provider.url
def process_provider(self, prv):
url = prv.url
self.show_info_message("Please, wait...", Gtk.MessageType.INFO)
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
stdout=subprocess.PIPE,
@@ -126,7 +130,10 @@ class PiconsDialog:
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
self._current_process.wait()
path = self._TMP_DIR + self._BASE_URL + url[url.rfind("/") + 1:]
PiconsParser.parse(path, self._picons_path, self._TMP_DIR, provider.on_id, self.get_picons_format())
pos = "".join(c for c in prv.pos if c.isdigit())
PiconsParser.parse(path, self._picons_path, self._TMP_DIR, prv.on_id, pos,
self._picon_ids, self.get_picons_format())
self.resize(self._picons_path)
self.show_info_message("Done", Gtk.MessageType.INFO)
def write_to_buffer(self, fd, condition):
@@ -147,6 +154,16 @@ class PiconsDialog:
insert = buf.get_insert()
self._text_view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
def resize(self, path):
if self._resize_no_radio_button.get_active():
return
self.show_info_message("Resizing...", Gtk.MessageType.INFO)
command = "mogrify -resize {}! *.png".format(
"320x240" if self._resize_220_132_radio_button.get_active() else "100x60").split()
self._current_process = subprocess.Popen(command, universal_newlines=True, cwd=path)
self._current_process.wait()
@run_task
def on_cancel(self, item):
if self._current_process:
@@ -192,7 +209,7 @@ class PiconsDialog:
@run_idle
def on_selected_toggled(self, toggle, path):
model = self._providers_tree_view.get_model()
model.set_value(model.get_iter(path), 4, not toggle.get_active())
model.set_value(model.get_iter(path), 5, not toggle.get_active())
self.update_receive_button_state()
def on_url_changed(self, entry):
@@ -200,13 +217,17 @@ class PiconsDialog:
entry.set_name("GtkEntry" if suit else "digit-entry")
self._load_providers_tool_button.set_sensitive(suit if suit else False)
def on_position_edited(self, render, path, value):
model = self._providers_tree_view.get_model()
model.set_value(model.get_iter(path), 2, value)
@run_idle
def update_receive_button_state(self):
self._receive_tool_button.set_sensitive(len(self.get_selected_providers()) > 0)
def get_selected_providers(self):
""" returns selected providers """
return [r for r in self._providers_tree_view.get_model() if r[4]]
return [r for r in self._providers_tree_view.get_model() if r[5]]
@run_idle
def show_dialog(self, message, dialog_type):

View File

@@ -243,6 +243,8 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_right">5</property>
<property name="margin_bottom">2</property>
<property name="use_stock">True</property>
</object>
<packing>
@@ -741,6 +743,17 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>

View File

@@ -1,5 +1,5 @@
#!/bin/env bash
VER="0.2.1_Pre-alpha"
VER="0.2.3_Pre-alpha"
B_PATH="dist/DemonEditor"
DEB_PATH="$B_PATH/usr/share/demoneditor"

View File

@@ -1,5 +1,5 @@
Package: DemonEditor
Version: 0.2.1-Pre-alpha
Version: 0.2.3-Pre-alpha
Section: utils
Priority: optional
Architecture: all