Пример #1
0
 class AddCardMenuScreen(Screen):
     question = ""
     answer = ""
     def __init__(self):
         Screen.__init__(self)
         self.name = "add"
         
         self.config = ConfigParser()
         self.config.add_section("add")
         self.config.set("add", "question", "Question")
         self.config.set("add", "answer", "Answer")
         self.config.set("add", "make", "action")
         self.config.add_callback(self.update_qa, section="add", key="question")
         self.config.add_callback(self.update_qa, section="add", key="answer")
         self.menu = SettingsWithNoMenu()
         
         
         self.menu.register_type("action", FlashcardAppManager.SettingDoAction)
         self.menu.add_json_panel("Add a card", self.config, os.path.join(os.path.dirname(__file__), 'add_menu.json'))
         
         self.add_widget(self.menu)
         
         
     def update_qa(self, *args):
         FlashcardAppManager.AddCardMenuScreen.question = self.config.get('add', 'question')
         FlashcardAppManager.AddCardMenuScreen.answer = self.config.get('add', 'answer')
Пример #2
0
def test_configparser_callbacks():
    """Test that the ConfigParser handles callbacks."""
    def callback():
        pass

    config = ConfigParser()
    assert len(config._callbacks) == 0

    config.add_callback(callback, 'section', 'key')
    assert len(config._callbacks) == 1

    config.remove_callback(callback, 'section', 'key')
    assert len(config._callbacks) == 0
Пример #3
0
 class EditCardMenuScreen(Screen):
     question = ""
     answer = ""
     nquestion = ""
     nanswer = ""
     EditCardMenuConfig = None
     
     def update_qa(self, *args):
             FlashcardAppManager.EditCardMenuScreen.nquestion = self.config.get('edit', 'nquestion')
             FlashcardAppManager.EditCardMenuScreen.nanswer = self.config.get("edit", "nanswer")
             
     def __init__(self):
         Screen.__init__(self)
         
         self.name = "edit"
         
         self.config = ConfigParser()
         self.config.add_section("edit")
         self.config.set("edit", "question", "Question")
         self.config.set("edit", "answer", "Answer")
         self.config.set("edit", "nquestion", "Question")
         self.config.set("edit", "nanswer", "Answer")
         self.config.set("edit", "edit", "action")
         
         FlashcardAppManager.EditCardMenuScreen.question = self.config.get('edit', 'question')
         FlashcardAppManager.EditCardMenuScreen.answer = self.config.get('edit', 'answer')
         FlashcardAppManager.EditCardMenuScreen.nquestion = self.config.get('edit', 'nquestion')
         FlashcardAppManager.EditCardMenuScreen.nanswer = self.config.get('edit', 'nanswer')
         
         
             
         self.config.add_callback(self.update_qa, section="edit", key="nquestion")
         self.config.add_callback(self.update_qa, section="edit", key="nanswer")
         
         self.menu = SettingsWithNoMenu()
         
         
         self.menu.register_type("action", FlashcardAppManager.SettingDoAction)
         self.menu.add_json_panel("Add a card", self.config, os.path.join(os.path.dirname(__file__), 'edit_menu.json'))
         
         FlashcardAppManager.EditCardMenuScreen.EditCardMenuConfig = self.config
         
         self.add_widget(self.menu)
         
         def on_pre_enter(self, *args):
             FlashcardAppManager.EditCardMenuScreen.question = FlashcardAppManager.deck_widget.deck.get_selected().get_question()
             FlashcardAppManager.EditCardMenuScreen.answer = FlashcardAppManager.deck_widget.deck.get_selected().get_answer()
             self.config.set("edit", "question", FlashcardAppManager.EditCardMenuScreen.question)
             self.config.set("edit", "answer", FlashcardAppManager.EditCardMenuScreen.answer)
Пример #4
0
 class MenuScreen(Screen):
     def __init__(self):
         Screen.__init__(self)
         self.name = 'menu'
         self.config = ConfigParser()
         self.config.add_section("deck")
         self.config.add_section("card")
         self.config.adddefaultsection("menu")
         self.config.set("deck", "start_studying", 1)
         self.config.set("deck", "change_deck_mode", "Normal")
         self.config.set("deck", "show_list", True)
         self.config.set("deck", "undo", True)
         self.config.set("deck", "redo", True)
         self.config.set("card", "add", "")
         self.config.set("card", "edit", True)
         self.config.set("card", "remove", True)
         
         self.config.add_callback(self.check_deck_locks, "deck", "redo")
         self.config.add_callback(self.check_deck_locks, "deck", "undo")
         
         self.config.add_callback(self.check_card_locks, "card", "edit")
         self.config.add_callback(self.check_card_locks, "card", "add")
         
         
         self.menu = SettingsWithNoMenu()
         self.menu.register_type("screen", FlashcardAppManager.SettingNewScreen)
         self.menu.register_type("action", FlashcardAppManager.SettingDoAction)
         self.menu.add_json_panel("Flashcards", self.config, os.path.join(os.path.dirname(__file__), 'menu.json'))
         
         self.add_widget(self.menu)
         
 
     def check_deck_locks(self, section, key, value):
         print(self.config.get(section, key))
     
     def check_card_locks(self, section, key, value):
         print()
Пример #5
0
class ComicRackReader(MDApp):
    nav_drawer = ObjectProperty()
    lang = StringProperty("en")
    open_comics_list = ListProperty()
    sync_folder = StringProperty()
    full_screen = False
    LIST_SCREENS = ListProperty()
    store_dir = StringProperty()
    comic_db = ObjectProperty()
    username = StringProperty()
    password = StringProperty()
    api_key = StringProperty()
    max_books_page = NumericProperty()
    open_last_comic_startup = NumericProperty()
    how_to_open_comic = StringProperty()
    app_started = BooleanProperty(False)
    open_comic_screen = StringProperty()
    sync_is_running = BooleanProperty(False)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Window.bind(on_keyboard=self.events_program)
        Window.soft_input_mode = "below_target"
        self.LIST_SCREENS = [
            "base",
            "license",
            "about",
            "server_lists_screen",
            "syncscreen",
            "server_readinglists_screen",
            "single_file_screen",
            "open_file_screen",
        ]

        self.list_previous_screens = ["base"]
        self.window = Window
        self.config = ConfigParser()
        self.manager = None
        self.window_language = None
        self.exit_interval = False
        self.comic_thumb_height = 240
        self.comic_thumb_width = 156
        self.dict_language = literal_eval(
            open(
                os.path.join(self.directory, "data", "locales", "locales.txt")
            ).read()
        )
        # self.translation = Translation(
        #     self.lang, 'Ttest', os.path.join(self.directory,
        # data', 'locales')
        # )
        self.base_url = ""
        self.settings_cls = MySettings
        self.md_manager = None
        self.open_comic_screen = ""

    # def get_application_config(self):
    #     return super(ComicRackReader, self).get_application_config(
    #         '{}/%(appname)s.ini'.format(self.directory))

    def build_config(self, config):
        """Creates an application settings file ComicRackReader.ini."""

        config.adddefaultsection("Language")
        config.adddefaultsection("Saved")
        config.setdefault("Language", "language", "en")

        config.setdefault("Saved", "last_comic_id", "")
        config.setdefault("Saved", "last_comic_type", "")
        config.setdefault("Saved", "last_reading_list_id", "")
        config.setdefault("Saved", "last_reading_list_name", "")
        config.setdefault("Saved", "last_pag_pagnum", "")

        config.setdefaults(
            "General",
            {
                "base_url": "http://",
                "storagedir": self.user_data_dir,
                "use_api_key": 0,
                "api_key": "",
                "username": "",
                "password": "",
                "open_last_comic_startup": 0,
                "how_to_open_comic": "Open Local Copy",
                # 'use_pagination':   '1',
                "max_books_page": 25,
            },
        )
        config.setdefaults(
            "Sync", {"sync_folder": self.user_data_dir, "max_num_sync": 50}
        )
        config.setdefaults(
            "Display",
            {
                "mag_glass_size": 200,
                "right2left": 0,
                "dblpagesplit": "0",
                "stretch_image": "0",
                "keep_ratio": "0",
                "reading_list_icon_size": "Small",
                "max_comic_pages_limit": 50,
                "max_height": 1500,
            },
        )

        config.setdefaults(
            "Screen Tap Control",
            {
                "bottom_right": "Next Page",
                "bottom_left": "Prev Page",
                "bottom_center": "Open Page Nav",
                "top_right": "Return to Home Screen",
                "top_left": "Precodv Page",
                "top_center": "Open Collection Browser",
                "middle_right": "None",
                "middle_left": "None",
                "middle_center": "Open NavBar",
                "dbl_tap_time": 250,
            },
        )

        config.setdefaults(
            "Hotkeys",
            {
                "hk_next_page": ".",
                "hk_prev_page": ",",
                "hk_open_page_nav": "p",
                "hk_open_collection": "j",
                "hk_return_comic_list": "c",
                "hk_return_base_screen": "r",
                "hk_toggle_navbar": "n",
                "hk_toggle_fullscreen": "f",
            },
        )

    def set_value_from_config(self, *args):
        """Sets the values of variables from the settings
        file ComicRackReader.ini."""
        self.config.read(os.path.join(self.directory, "comicrackreader.ini"))
        self.lang = self.config.get("Language", "language")
        self.sync_folder = self.config.get("Sync", "sync_folder")
        self.store_dir = os.path.join(
            self.config.get("General", "storagedir"), "store_dir"
        )
        if not Path(self.store_dir).is_dir():
            os.makedirs(self.store_dir)
        self.base_url = self.config.get("General", "base_url").rstrip("\\")
        print(f"self.base_url:{self.base_url}")
        self.api_key = self.config.get("General", "api_key")
        self.username = self.config.get("General", "username")
        self.password = self.config.get("General", "password")

        self.api_url = self.base_url + "/API"
        self.my_data_dir = os.path.join(self.store_dir, "comics_db")

        if not os.path.isdir(self.my_data_dir):
            os.makedirs(self.my_data_dir)

        self.max_books_page = int(self.config.get("General", "max_books_page"))
        self.open_last_comic_startup = self.config.get(
            "General", "open_last_comic_startup"
        )
        self.how_to_open_comic = self.config.get(
            "General", "how_to_open_comic"
        )

    def config_callback(self, section, key, value):
        if key == "storagedir":

            def __callback_for_please_wait_dialog(*args):

                if args[0] == "Delete Database":
                    self.stop()
                elif args[0] == "Move Database":
                    print("move")
                    db_folder = self.my_data_dir
                    old_dbfile = os.path.join(db_folder, "ComicRackReader.db")
                    store_dir = os.path.join(value, "store_dir")
                    new_data_dir = os.path.join(store_dir, "comics_db")
                    new_dbfile = os.path.join(
                        new_data_dir, "ComicRackReader.db"
                    )
                    if not os.path.isdir(store_dir):
                        os.makedirs(store_dir)
                    if not os.path.isdir(new_data_dir):
                        os.makedirs(new_data_dir)
                    copyfile(old_dbfile, new_dbfile)
                    self.stop()

            self.please_wait_dialog = MDDialog(
                title="Please Restart ComicRackReader",
                size_hint=(0.8, 0.4),
                text_button_ok="Delete Database",
                text_button_cancel="Move Database",
                text=f"Storage/Databse dir changed Delete Data or Move it to new dir \nApp will Close please restart it for new setting to take effect?",
                events_callback=__callback_for_please_wait_dialog,
            )
            self.please_wait_dialog.open()
        else:
            config_items = {
                "base_url": "base_url",
                "api_key": "api_key",
                "sync_folder": "sync_folder",
                "password": "******",
                "username": "******",
                "max_books_page": "max_books_page",
                "sync_folder": "sync_folder",
            }
            item_list = list(config_items.keys())
            if key in item_list:
                item = config_items[key]
                setattr(self, item, value)
            self.api_url = self.base_url + "/API"
            # self.my_data_dir = os.path.join(self.store_dir, 'comics_db')

    def build(self):
        r = Factory.register
        r("MDToolbarTooltips", module="libs.uix.widgets.mytoolbar")
        self.set_value_from_config()
        from libs.uix.baseclass.basescreen import BaseScreen
        from libs.uix.baseclass.about import About
        from libs.uix.baseclass.local_lists_screen import LocalListsScreen
        from libs.uix.baseclass.local_readinglists_screen import (
            LocalReadingListsScreen,
        )
        from libs.uix.baseclass.navdrawer import NavDrawer
        from libs.uix.baseclass.server_comicbook_screen import (
            ServerComicBookScreen,
        )
        from libs.uix.baseclass.server_lists_screen import ServerListsScreen
        from libs.uix.baseclass.server_readinglists_screen import (
            ServerReadingListsScreen,
        )
        from libs.uix.baseclass.license import License
        from libs.uix.lists import SingleIconItem

        start_db()
        path = os.path.dirname(__file__)
        icon_path = os.path.join(path, f"data{os.sep}")
        self.icon = os.path.join(icon_path, f"icon.png")
        self.title = "ComicRackReader 1.2.1"
        self.theme_cls.primary_palette = "Amber"
        self.load_all_kv_files(
            os.path.join(self.directory, "libs", "uix", "kv")
        )
        self.screen = StartScreen()  # program main screen
        self.manager = self.screen.ids.manager
        action_bar = self.screen.ids.action_bar
        # Left side Action bar Icons
        action_bar.left_action_items = [
            ["home", "Home", lambda x: self.switch_base_screen()],
            ["settings", "Settings", lambda x: self.open_settings()],
            ["fullscreen", "Full Screen", lambda x: self.toggle_full_screen()],
        ]
        # right side Action bar Icons
        action_bar.right_action_items = [
            ["file-cabinet", "Open File", lambda x: self.file_manager_open()],
            ["server", "ComicRack Reading Lists", lambda x: self.switch_server_lists_screen()],
            ["view-list", "Current Server Reading List", lambda x: self.switch_readinglists_screen()],
            ["folder-sync", "Local Reading Lists", lambda x: self.switch_local_lists_screen()],
            [
                "playlist-check", "Current Local Reading List",
                lambda x: self.switch_local_readinglists_screen(),
            ],
            ["book-open-page-variant", "Open Comic Book", lambda x: self.switch_comic_reader()],
            ["close-box-outline", "Exit App", lambda x: self.stop()],
        ]
        self.config.add_callback(self.config_callback)
        return self.screen

    def load_all_kv_files(self, directory_kv_files):
        for kv_file in os.listdir(directory_kv_files):
            kv_file = os.path.join(directory_kv_files, kv_file)
            if os.path.isfile(kv_file):
                with open(kv_file, encoding="utf-8") as kv:
                    Builder.load_string(kv.read())

    def on_config_change(self, config, section, key, value):
        pass

    def events_program(self, instance, keyboard, keycode, text, modifiers):
        c = Keyboard()
        """Called when you press a Key"""
        app = App.get_running_app()
        current_screen = app.manager.current_screen
        hk_next_page = app.config.get("Hotkeys", "hk_next_page")
        hk_prev_page = app.config.get("Hotkeys", "hk_prev_page")
        hk_open_page_nav = app.config.get("Hotkeys", "hk_open_page_nav")
        hk_open_collection = app.config.get("Hotkeys", "hk_open_collection")
        hk_return_comic_list = app.config.get(
            "Hotkeys", "hk_return_comic_list"
        )
        hk_return_base_screen = app.config.get(
            "Hotkeys", "hk_return_base_screen"
        )
        hk_toggle_navbar = app.config.get("Hotkeys", "hk_toggle_navbar")

        hk_toggle_fullscreen = app.config.get(
            "Hotkeys", "hk_toggle_fullscreen"
        )
        Logger.debug(f"keyboard:{keyboard}")
        if current_screen.name not in self.LIST_SCREENS:
            if keyboard in (c.string_to_keycode(hk_next_page), 275):
                current_screen.load_next_slide()
            elif keyboard in (c.string_to_keycode(hk_prev_page), 276):
                current_screen.load_prev_slide()
            elif keyboard == c.string_to_keycode(hk_open_page_nav):
                current_screen.page_nav_popup_open()
            elif keyboard == c.string_to_keycode(hk_open_collection):
                current_screen.comicscreen_open_collection_popup()
            elif keyboard == c.string_to_keycode(hk_toggle_navbar):
                current_screen.toggle_option_bar()
            elif keyboard == c.string_to_keycode(hk_return_comic_list):
                app.switch_readinglists_screen()
            elif keyboard == c.string_to_keycode(hk_return_base_screen):
                app.show_action_bar()
                app.manager.current = "base"
            elif keyboard in (1001, 27):
                if self.nav_drawer.state == "open":
                    self.nav_drawer.toggle_nav_drawer()
                self.back_screen(event=keyboard)
            elif keyboard == c.string_to_keycode(hk_toggle_fullscreen):
                self.toggle_full_screen()
        else:
            if keyboard in (282, 319):
                pass
            elif keyboard == c.string_to_keycode(hk_toggle_fullscreen):
                self.toggle_full_screen()
            elif keyboard == c.string_to_keycode(hk_return_comic_list):
                app.manager.current = "server_readinglists_screen"
            elif keyboard == c.string_to_keycode(hk_return_base_screen):
                app.show_action_bar()
                app.switch_base_screen()
            elif keyboard in (1001, 27):
                if self.nav_drawer.state == "open":
                    self.nav_drawer.toggle_nav_drawer()
                self.back_screen(event=keyboard)
        return True

    def toggle_full_screen(self):
        if App.get_running_app().full_screen is False:
            Window.fullscreen = "auto"
            App.get_running_app().full_screen = True
        else:
            App.get_running_app().full_screen = False
            Window.fullscreen = False

    def back_screen(self, event=None):
        """Screen manager Called when the Back Key is pressed."""
        # BackKey pressed.
        if event in (1001, 27):
            if self.manager.current == "base":
                self.dialog_exit()
                return
            try:
                self.manager.current = self.list_previous_screens.pop()
            except:  # noqa
                self.manager.current = "base"
            # self.screen.ids.action_bar.title = self.title

    def show_license(self, *args):
        self.screen.ids.license.ids.text_license.text = ("%s") % open(
            os.path.join(self.directory, "LICENSE"), encoding="utf-8"
        ).read()

        self.nav_drawer._toggle()
        self.manager.current = "license"
        self.screen.ids.action_bar.left_action_items = [
            ["chevron-left", lambda x: self.back_screen(27)]
        ]
        self.screen.ids.action_bar.title = "MIT LICENSE"

    def dialog_exit(self):
        def check_interval_press(interval):
            self.exit_interval += interval
            if self.exit_interval > 5:
                self.exit_interval = False
                Clock.unschedule(check_interval_press)

        if self.exit_interval:
            sys.exit(0)

        Clock.schedule_interval(check_interval_press, 1)
        toast("Press Back to Exit")

    def on_lang(self, instance, lang):
        self.translation.switch_lang(lang)

    def build_settings(self, settings):
        settings.add_json_panel(
            "Sync Settings", self.config, data=settings_json_sync
        )
        settings.add_json_panel(
            "General Settings", self.config, data=settings_json_server
        )

        settings.add_json_panel(
            "Display Settings", self.config, data=settings_json_dispaly
        )
        settings.add_json_panel(
            "Screen Tap Control",
            self.config,
            data=settings_json_screen_tap_control,
        )
        settings.add_json_panel(
            "Hotkeys", self.config, data=settings_json_hotkeys
        )

    def switch_server_lists_screen(self):
        self.set_screen("List of Reading Lists Screen")
        self.manager.current = "server_lists_screen"

    def switch_readinglists_screen(self):
        screen = self.manager.get_screen("server_readinglists_screen")
        self.set_screen(screen.reading_list_title)
        self.manager.current = "server_readinglists_screen"

    def switch_local_readinglists_screen(self):
        screen = self.manager.get_screen("local_readinglists_screen")
        self.set_screen(screen.reading_list_title)
        self.manager.current = "local_readinglists_screen"

    def switch_comic_reader(self):
        if self.open_comic_screen:
            self.manager.current = "comic_book_screen"
        else:
            toast("No ComicBook Open")

    def switch_base_screen(self):
        self.set_screen("ComicRackReader Home Screen")
        self.manager.current = "base"

    def switch_local_lists_screen(self):
        self.set_screen("Local Sync Comics")
        self.manager.current = "local_lists_screen"

    def set_screen(self, title):
        self.screen.ids.action_bar.title = title

    def hide_action_bar(self):
        self.screen.ids.action_bar.opacity = 0
        self.screen.ids.action_bar.disabled = True
        self.screen.ids.action_bar.size_hint_y = None
        self.screen.ids.action_bar.size = (0, 0)

    def show_action_bar(self):
        self.screen.ids.action_bar.opacity = 1
        self.screen.ids.action_bar.disabled = False
        self.screen.ids.action_bar.size = (
            Window.width,
            self.theme_cls.standard_increment,
        )

    # FileManger
    def file_manager_open(self):
        previous = False
        if not self.md_manager:
            self.md_manager = ModalView(size_hint=(1, 1), auto_dismiss=False)
            self.file_manager = MDFileManager(
                exit_manager=self.exit_manager,
                select_path=self.select_path,
                previous=previous,
            )
            self.md_manager.add_widget(self.file_manager)

            self.file_manager.show(self.sync_folder)
        self.manager_open = True
        self.md_manager.open()

    def select_path(self, path):
        """It will be called when you click on the file name
        or the catalog selection button.
        :type path: str;
        :param path: path to the selected directory or file;
        """
        has_cb_files = False
        self.exit_manager()
        if os.path.isfile(path):
            ext = os.path.splitext(path)[-1].lower()
            if ext in (".cbz", ".cbr", ".cb7", ".cbp"):
                has_cb_files = True
                data = {"items": []}
                comic_data = convert_comicapi_to_json(path)
                data["items"].append(comic_data)
                new_rl = ComicReadingList(
                    name="Single_FileLoad",
                    data=data,
                    slug="FileOpen",
                    mode="FileOpen",
                )
                new_comic = ComicBook(data["items"][0], mode="FileOpen")
                new_rl.add_comic(new_comic)
            else:
                pass
        elif os.path.isdir(path):
            if os.path.isdir(path):
                onlyfiles = [
                    f
                    for f in os.listdir(path)
                    if os.path.isfile(os.path.join(path, f))
                ]
            data = {"items": []}
            for file in onlyfiles:
                ext = os.path.splitext(file)[-1].lower()
                if ext in (".cbz", ".cbr", ".cb7", ".cbp"):
                    file_path = os.path.join(path, file)
                    comic_data = convert_comicapi_to_json(file_path)
                    data["items"].append(comic_data)
                    has_cb_files = True
                else:
                    pass
            if has_cb_files is True:
                new_rl = ComicReadingList(
                    name=path, data=data, slug="path", mode="FileOpen"
                )
                for item in new_rl.comic_json:
                    comic_index = new_rl.comic_json
                    new_comic = ComicBook(
                        item,
                        readinglist_ob=new_rl,
                        comic_index=comic_index,
                        mode="FileOpen",
                    )
                    new_rl.add_comic(new_comic)
        if has_cb_files is True:
            max_books_page = int(self.config.get("General", "max_books_page"))
            paginator_obj = Paginator(new_rl.comics, max_books_page)
            screen = self.manager.get_screen("comic_book_screen")
            screen.setup_screen(
                readinglist_obj=new_rl,
                comic_obj=new_rl.comics[0],
                paginator_obj=paginator_obj,
                pag_pagenum=1,
                view_mode="FileOpen",
            )
            self.manager.current = "comic_book_screen"
            toast(f"Opening {new_rl.comics[0].__str__}")
        else:
            toast("A vaild ComicBook File was not found")
        self.md_manager = None

    def exit_manager(self, *args):
        """Called when the user reaches the root of the directory tree."""

        self.md_manager.dismiss()
        self.manager_open = False

    def delayed_work(self, func, items, delay=0):
        """Apply the func() on each item contained in items
        """
        if not items:
            return

        def _sync_delayed_work(*l):
            item = items.pop(0)
            if func(item) is False or not len(items):
                return False
            Clock.schedule_once(_sync_delayed_work, delay)

        Clock.schedule_once(_sync_delayed_work, delay)
class Settings:

    __defaults = {
        'kivy': {
            'log_level': 'debug',  # TODO: Change default to info
            'log_enable': 1,
            'log_dir': 'logs',
            'log_name': 'ps_%y-%m-%d_%_.txt',
            'log_maxfiles': 100
        },
        'data': {
            'dir': 'C:/pressure-data/',
            'ppr': 20
        },
        'com': {
            'port': 'COM1',
            'baudrate': 9600,
            'bytesize': '8',
            'parity': 'None',
            'stopbits': '1'
        },
        'calibration': {
            'user_point1': 0,
            'sensor_point1': 0,
            'user_point2': 2,
            'sensor_point2': 1024
        }
    }

    def __init__(self):
        self.config = ConfigParser()
        self.widget = SettingsWithNoMenu()

    def load(self, filename):
        for k, v in self.__defaults.items():
            self.config.setdefaults(k, v)
        self.config.read(filename)
        self.config.write()

        Config.read(filename)

        Logger.info('Settings: Loaded setting file: %s', filename)

        Logger.debug('Settings: Setting up panel')
        self.panel = self.widget.create_json_panel('Settings',
                                                   self.config,
                                                   data=self.windgetconfigdata)
        self.widget.children[0].add_widget(self.panel)

        Logger.debug('Settings: Setting options')
        self.setPanelOptions('port', SerialAdapter.getPortNames())
        self.setPanelOptions('bytesize', SerialAdapter.BYTESIZE.keys())
        self.setPanelOptions('parity', SerialAdapter.PARITY.keys())
        self.setPanelOptions('stopbits', SerialAdapter.STOPBITS.keys())

    def updateAvailablePorts(self):
        Logger.debug('Settings: Setting port options')
        self.setPanelOptions('port', SerialAdapter.getPortNames())

    def getPanelSetting(self, key):
        return next(
            (x for x in self.panel.children if not isinstance(x, SettingTitle)
             and not isinstance(x, Label) and x.key == key), None)

    def setPanelOptions(self, key, options):
        s = self.getPanelSetting(key)
        if s != None:
            s.options = options

    def getWidget(self):
        return self.widget

    def addCallback(self, callback, section=None, key=None):
        Logger.debug('Settings: Adding callback: %s, %s', section, key)
        self.config.add_callback(callback, section, key)
        if key != None:
            callback(section, key, self.get(section, key))

    def get(self, section, key):
        return self.config.get(section, key)

    def set(self, section, key, value):
        return self.config.set(section, key, value)

    def getDefault(self, section, key):
        return self.__defaults[section][key]

    def saveConfig(self):
        self.config.write()

    windgetconfigdata = """[