basic extensions API

This commit is contained in:
DYefremov
2023-02-09 23:51:14 +03:00
parent ba2272cf13
commit f4be52a202
3 changed files with 117 additions and 35 deletions

View File

@@ -176,6 +176,8 @@
<attribute name="action">app.on_logs_show</attribute>
</item>
</section>
<section id="extension_section">
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">FTP client</attribute>
@@ -390,6 +392,8 @@
<attribute name="action">app.on_logs_show</attribute>
</item>
</section>
<section id="mac_extension_section">
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">FTP client</attribute>

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2023 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Dmitriy Yefremov
#
class BaseExtension:
""" Base extension (plugin) class. """
# The label that will be displayed in the "Tools" menu.
LABEL = "Base extension"
def __init__(self, app):
# Current application instance.
# It can be used all public methods, properties or signals.
self._app = app
def exec(self):
""" Triggers an action for the given extension.
E.g. shows a dialog or runs an external script.
"""
self._app.show_info_message(f"Hello from {self.__class__.__name__} class!")
if __name__ == "__main__":
pass

View File

@@ -590,40 +590,7 @@ class Application(Gtk.Application):
def do_startup(self):
Gtk.Application.do_startup(self)
# App menu.
builder = get_builder(UI_RESOURCES_PATH + "app_menu.ui", tag="attribute")
if not IS_GNOME_SESSION:
if IS_DARWIN:
self.set_app_menu(builder.get_object("mac_app_menu"))
self.set_menubar(builder.get_object("mac_menu_bar"))
else:
self.set_menubar(builder.get_object("menu_bar"))
else:
tools_menu = builder.get_object("tools_menu")
tools_button = Gtk.MenuButton(visible=True, menu_model=tools_menu, direction=Gtk.ArrowType.NONE)
tools_button.set_tooltip_text(get_message("Tools"))
tools_button.set_image(Gtk.Image.new_from_icon_name("applications-utilities-symbolic", Gtk.IconSize.BUTTON))
view_menu = builder.get_object("view_menu")
view_button = Gtk.MenuButton(visible=True, menu_model=view_menu, direction=Gtk.ArrowType.NONE)
view_button.set_tooltip_text(get_message("View"))
box = Gtk.ButtonBox(visible=True, layout_style="expand")
box.add(tools_button)
box.add(view_button)
self._main_window.get_titlebar().pack_end(box)
# IPTV menu.
self._iptv_menu_button.set_menu_model(builder.get_object("iptv_menu"))
iptv_elem = self._tool_elements.get("fav_iptv_popup_item")
for h in (self.on_iptv, self.on_import_yt_list, self.on_import_m3u, self.on_export_iptv_to_m3u,
self.on_epg_list_configuration, self.on_iptv_list_configuration, self.on_remove_all_unavailable):
iptv_elem.bind_property("sensitive", self.set_action(h.__name__, h, False), "enabled")
def do_activate(self):
self._main_window.set_application(self)
self._main_window.set_wmclass("DemonEditor", "DemonEditor")
self._main_window.present()
self.init_app_menu()
self.init_actions()
self.set_accels()
@@ -631,6 +598,11 @@ class Application(Gtk.Application):
self.init_appearance()
self.filter_set_default()
def do_activate(self):
self._main_window.set_application(self)
self._main_window.set_wmclass("DemonEditor", "DemonEditor")
self._main_window.present()
self.init_profiles()
gen = self.init_http_api()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
@@ -674,6 +646,64 @@ class Application(Gtk.Application):
self.activate()
return 0
def init_app_menu(self):
builder = get_builder(UI_RESOURCES_PATH + "app_menu.ui", tag="attribute")
if not IS_GNOME_SESSION:
if IS_DARWIN:
self.set_app_menu(builder.get_object("mac_app_menu"))
self.set_menubar(builder.get_object("mac_menu_bar"))
else:
self.set_menubar(builder.get_object("menu_bar"))
else:
tools_menu = builder.get_object("tools_menu")
tools_button = Gtk.MenuButton(visible=True, menu_model=tools_menu, direction=Gtk.ArrowType.NONE)
tools_button.set_tooltip_text(get_message("Tools"))
tools_button.set_image(Gtk.Image.new_from_icon_name("applications-utilities-symbolic", Gtk.IconSize.BUTTON))
view_menu = builder.get_object("view_menu")
view_button = Gtk.MenuButton(visible=True, menu_model=view_menu, direction=Gtk.ArrowType.NONE)
view_button.set_tooltip_text(get_message("View"))
box = Gtk.ButtonBox(visible=True, layout_style="expand")
box.add(tools_button)
box.add(view_button)
self._main_window.get_titlebar().pack_end(box)
# IPTV menu.
self._iptv_menu_button.set_menu_model(builder.get_object("iptv_menu"))
iptv_elem = self._tool_elements.get("fav_iptv_popup_item")
for h in (self.on_iptv, self.on_import_yt_list, self.on_import_m3u, self.on_export_iptv_to_m3u,
self.on_epg_list_configuration, self.on_iptv_list_configuration, self.on_remove_all_unavailable):
iptv_elem.bind_property("sensitive", self.set_action(h.__name__, h, False), "enabled")
if self._settings.is_enable_experimental:
self.init_extensions(builder)
def init_extensions(self, builder):
import pkgutil
# Extensions (Plugins) section.
ext_section = builder.get_object(f"{'mac_' if IS_DARWIN else ''}extension_section")
ext_path = f"{self._settings.default_data_path}tools{os.sep}extensions"
ext_paths = [f"{os.path.dirname(__file__)}{os.sep}extensions", ext_path]
extensions = {}
for importer, name, is_package in pkgutil.iter_modules(ext_paths):
if is_package:
m = importer.find_module(name).load_module()
cls_name = name.capitalize()
if hasattr(m, cls_name):
cls = getattr(m, cls_name)
action_name = f"on_{name}_extension"
item = Gio.MenuItem.new(cls.LABEL, f"app.{action_name}")
ext_section.append_item(item)
extensions[action_name] = cls
def ac(a, v):
c = extensions[a.get_name()]
e = c(self)
e.exec()
self.set_action(action_name, ac)
def init_actions(self):
self.set_action("on_import_bouquet", self.on_import_bouquet)
self.set_action("on_import_bouquets", self.on_import_bouquets)
@@ -4335,7 +4365,7 @@ class Application(Gtk.Application):
self.show_info_message(message, Gtk.MessageType.ERROR)
@run_idle
def show_info_message(self, text, message_type):
def show_info_message(self, text, message_type=Gtk.MessageType.INFO):
self._info_bar.set_visible(False)
self._info_label.set_text(get_message(text))
self._info_bar.set_message_type(message_type)