Exemple #1
0
def wifi_connect_done(client: NM.Client, res: Gio.AsyncResult,
                      button: Gtk.Button):
    created = client.add_connection_finish(res)
    logger.debug('NetworkManager created connection: {}', created)
    if created:
        button.set_label(_('Saved'))
        button.set_sensitive(False)
    def on_keyfile_select_button_clicked(self, button: Gtk.Button) -> None:
        self.unlocked_database.start_database_lock_timer()

        # We reset the button if we previously failed.
        if button.props.icon_name == "edit-delete-symbolic":
            button.props.icon_name = "document-open-symbolic"
            button.remove_css_class("destructive-action")
            self.current_keyfile_path = None
            self.current_keyfile_hash = None
            return

        select_dialog = Gtk.FileChooserNative.new(
            # NOTE: Filechooser title for choosing current used keyfile
            _("Select Current Keyfile"),
            self,
            Gtk.FileChooserAction.OPEN,
            None,
            None,
        )
        select_dialog.set_modal(True)

        ffilter = KeyFileFilter().file_filter
        select_dialog.add_filter(ffilter)

        select_dialog.connect("response", self._on_select_filechooser_response,
                              select_dialog)
        select_dialog.show()
Exemple #3
0
    def _setButtons(self) -> None:
        """
        Sets up the cancel and generate buttons.

        :return:
        """

        box: Box = Box()

        self._main_box.pack_end(box, False, True, 0)

        box.set_halign(Align.CENTER)
        box.set_orientation(Orientation.HORIZONTAL)

        setMargin(box, 5)

        self._cancel_btn = Button(label='Cancel')

        box.pack_start(self._cancel_btn, False, True, 0)

        setMargin(self._cancel_btn, 5, 5, 100, 5)
        self._cancel_btn.connect('clicked', self._onCancelBtnClicked)

        self._generate_btn = Button(label='Generate')

        box.pack_end(self._generate_btn, False, True, 0)

        setMargin(self._generate_btn, 100, 5, 5, 5)
        self._generate_btn.connect('clicked', self._onGenerateBtnClicked)

        timeout_add(300, self._setSensitiveGenerateBtn)
Exemple #4
0
 def on_btn_copy_clicked(self, button: Gtk.Button):
     clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
     begin = self.raw_result_buffer.get_start_iter()
     end = self.raw_result_buffer.get_end_iter()
     self.raw_result_buffer.select_range(begin, end)
     self.raw_result_buffer.copy_clipboard(clipboard)
     button.set_tooltip_text(_('Copied'))
     GLib.timeout_add_seconds(3, remove_tooltip, button)
Exemple #5
0
def usb_entry_check(self: Gtk.Entry, button: Gtk.Button):
    usbpattern = re.compile(r'^[a-f\d]{4}:[a-f\d]{4}$')
    if usbpattern.match(self.get_text()):
        self.set_name('validEntry')
        button.set_sensitive(True)
    else:
        self.set_name('invalidEntry')
        button.set_sensitive(False)
 def set_button_string(button: Gtk.Button, text: str) -> None:
     """
     Sets the displayed text of a button widget
     :param button: the button widget to be modified
     :param text: the text to be displayed
     :return: void
     """
     button.set_label(text)
Exemple #7
0
 def on_execute(self, button: Gtk.Button):
     if button.get_label() == 'Execute':
         pinholesizes = [float(x[0]) for x in self.builder.get_object('pinhole_store') if x[0]]
         spacers = [float(x[0]) for x in self.builder.get_object('spacers_store') if x[0]]
         self.instrument.config['gui']['optimizegeometry']['pinholes'] = pinholesizes
         self.instrument.config['gui']['optimizegeometry']['spacers'] = spacers
         mindist_l1 = self.builder.get_object('l1baselength_adjustment').get_value()
         mindist_l2 = self.builder.get_object('l2baselength_adjustment').get_value()
         wavelength = self.builder.get_object('wavelength_adjustment').get_value()
         sealringwidth = self.builder.get_object('sealingringwidth_adjustment').get_value()
         sd = self.builder.get_object('distance_sd_adjustment').get_value()
         lbs = self.builder.get_object('distance_dbs_adjustment').get_value()
         ls = self.builder.get_object('distance_ph3s_adjustment').get_value()
         self.limits_samplesize = (
             self.builder.get_object('diameter_sample_min_adjustment').get_value(),
             self.builder.get_object('diameter_sample_max_adjustment').get_value()
         )
         self.limits_beamstopsize = (
             self.builder.get_object('diameter_beamstop_min_adjustment').get_value(),
             self.builder.get_object('diameter_beamstop_max_adjustment').get_value()
         )
         self.limit_l1min = self.builder.get_object('min_l1_adjustment').get_value()
         self.limit_l2min = self.builder.get_object('min_l2_adjustment').get_value()
         self.pinholegenerator = PinholeConfiguration.enumerate(
             spacers, pinholesizes, ls, lbs, sd, mindist_l1, mindist_l2, sealringwidth, wavelength)
         self.builder.get_object('results_store').clear()
         button.set_label('Stop')
         button.get_image().set_from_icon_name('gtk-stop', Gtk.IconSize.BUTTON)
         self.set_sensitive(False, 'Filtering possible pinhole configurations',
                            ['inputframe'])
         self.builder.get_object('work_progress').show()
         self.builder.get_object('work_progress').set_fraction(0)
         self.workdone = 0
         self.worksize = self._executor.submit(estimate_worksize_C, spacers, pinholesizes, sealringwidth)
         state = {'pinholesizes': pinholesizes,
                  'spacers': spacers,
                  'mindist_l1': mindist_l1,
                  'mindist_l2': mindist_l2,
                  'wavelength': wavelength,
                  'sealringwidth': sealringwidth,
                  'sd': sd,
                  'lbs': lbs,
                  'ls': ls,
                  'limits_samplesize': self.limits_samplesize,
                  'limits_beamstopsize': self.limits_beamstopsize,
                  'limit_l1min': self.limit_l1min,
                  'limit_l2min': self.limit_l2min
                  }
         self.instrument.config['gui']['optimizegeometry'].update(state)
         self._idle_handler = GLib.idle_add(self._idle_func)
     else:
         self.end_work()
Exemple #8
0
 def on_command_execute(self, button: Gtk.Button):
     if button.get_label() == 'Execute':
         cmd = self.builder.get_object('command_entry').get_text()
         try:
             self.instrument.services['interpreter'].execute_command(cmd)
         except CommandError as ce:
             error_message(self.widget, 'Cannot execute command', str(ce))
         else:
             button.set_label('Stop')
             if (not self._commandhistory) or (self._commandhistory and self._commandhistory[-1] != cmd):
                 self._commandhistory.append(self.builder.get_object('command_entry').get_text())
     elif button.get_label() == 'Stop':
         self.instrument.services['interpreter'].kill()
     else:
         raise ValueError(button.get_label())
Exemple #9
0
    def __init__(self, prop, *args, **kwargs):
        Button.__init__(self, *args, **kwargs)

        # Styling
        context = self.get_style_context()      
        provider = CssProvider()
        resource = 'ml/prevete/Daty/gtk/property.css'
        provider.load_from_resource(resource)
        context.add_provider(provider, STYLE_PROVIDER_PRIORITY_APPLICATION) 

        context = self.description.get_style_context()
        set_style(context, resource, 'popover_description', True)

        self.set_label(prop["Label"], prop["Description"])
        self.description.set_text(prop['Description'])
        self.description.set_line_wrap(True)
Exemple #10
0
    def sousFenêtreFichier(self, bouton: Gtk.Button, numFichier: int) -> None:
        """
        Callback utilisé pour lancer une fenêtre sélecteur de fichier.

        Modifie le texte du bouton une fois le fichier sélectionné.
        """
        dialogue = Gtk.FileChooserDialog(
            "Choisissez un fichier", self, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        réponse = dialogue.run()
        if réponse == Gtk.ResponseType.OK:
            self.fichiers[numFichier] = dialogue.get_filename()
        dialogue.destroy()
        nomFichier = self.fichiers[numFichier].split("/")[-1]
        bouton.set_label(nomFichier)
Exemple #11
0
 def on_console_button_toggled(self, button: Gtk.Button) -> None:
     if button.get_active():
         console = ctypes.windll.kernel32.GetConsoleWindow()
         ctypes.windll.user32.ShowWindow(console, 1)
         ctypes.windll.kernel32.CloseHandle(console)
     else:
         console = ctypes.windll.kernel32.GetConsoleWindow()
         ctypes.windll.user32.ShowWindow(console, 0)
         ctypes.windll.kernel32.CloseHandle(console)
Exemple #12
0
    def on_show_close_button_toggled(self, button: Gtk.Button) -> None:
        current_value = button.get_active()

        if current_value:
            self.parent_window.set_deletable(True)
        else:
            self.parent_window.set_deletable(False)

        config.new('general', 'show_close_button', current_value)
Exemple #13
0
    def on_power_clicked(self, button: Gtk.Button) -> None:
        serial_message = 'fl'
        status = str(int(button.get_active()))

        if self.fan_index == -1:
            config.new("front", "power_status", status * 3)
        else:
            config.set_to_index("front", "power_status", status,
                                self.fan_index)

        serial_message += config.parser.get("front", "power_status")

        self.application.send_serial(serial_message)
Exemple #14
0
    def on_yes_button_clicked(self, button: Gtk.Button) -> None:
        button.hide()
        self.no_button.hide()

        with contextlib.suppress(AttributeError):
            self.give_label.hide()
            self.give_tree.hide()
            self.arrow.hide()
            self.receive_tree.hide()

        self.set_size_request(0, 0)
        self.header_bar.set_show_close_button(False)
        self.parent_window.text_tree_lock = True

        task: asyncio.Future[Union[Dict[str, Any], List[Tuple[Any, Dict[str, Any]]]]]

        if self.iter:
            task = asyncio.ensure_future(self.finalize())
        else:
            task = asyncio.ensure_future(self.batch_finalize())

        task.add_done_callback(self.on_task_finish)
Exemple #15
0
    def __init__(self,
                 *args,
                 image=None,
                 tooltip=None,
                 callback=None,
                 cb_args={},
                 **kwargs):
        Button.__init__(self, *args, **kwargs)

        # Styling
        context = self.get_style_context()
        provider = CssProvider()
        provider.load_from_resource('/ml/prevete/Daty/gtk/roundedbutton.css')
        context.add_provider(provider, STYLE_PROVIDER_PRIORITY_APPLICATION)

        if callback:
            self.connect("clicked", callback, *cb_args)

        if image:
            self.image.set_from_icon_name(image, IconSize.BUTTON)

        if tooltip:
            self.set_tooltip_text(tooltip)
    def _destination_file_chooser_response_cb(
        self,
        native: Gtk.FileChooserNative,
        response: int,
        button: Gtk.Button,
    ):
        if response == Gtk.ResponseType.ACCEPT:
            file: Gio.File = native.get_file()
            filename: str = file.get_path()
            if (filename and os.path.isdir(filename)
                    and os.access(filename, os.W_OK)):
                label: Gtk.Label = button.get_child()
                label.set_text(filename)
                self._destination = filename
            else:
                self._destination = None
            self._update_buttons()

        native.destroy()
Exemple #17
0
def on_layout_btn_clicked(button: Gtk.Button, *args):
    """
    @brief      Change desktop layout on layout button click.

    @details    In the layout regarding button must be named
    after the target layout name int LAYOUT_COMMANDS dictionary.

    @param      button   Gtk.Button button widget that recieved
    clicked event.

    @param      args     place holder list

    @return     None
    """
    name: str = button.get_name()
    print("Layout Name: ", name)
    commands = LAYOUT_COMMANDS[name]
    for cmd in commands:
        cmd.execute()
Exemple #18
0
 def _on_start(self, widget: Gtk.Button, event: Gdk.EventButton) -> bool:
     if self.going:
         return True
     self.going = True
     self.spin.set_range(self.iterc, self.iterc)
     self.progr1.set_opacity(1)
     self.progr2.set_opacity(1)
     self.set_progress(0, True)
     self.set_progress(0, False)
     timings = TIMINGS[widget.get_label()]
     cache = {timing[0]: [] for timing in timings}
     iterc = self.iterc
     for i in range(1, iterc + 1):
         for name, val in zip(*self.measure(timings)):
             cache[name].append(val)
         self.set_bars(cache)
         self.set_progress(i / iterc, True)
     self.progr1.set_opacity(0)
     self.progr2.set_opacity(0)
     self.going = False
     self.spin.set_range(1, 2**16)
     return True
    async def on_add_authenticator_clicked(self, button: Gtk.Button) -> None:
        self.status.info(_("Retrieving user data"))
        button.set_sensitive(False)
        self.user_details_section.hide()
        self.set_size_request(0, 0)

        if not self.oauth_token or not self.steamid:
            self.status.error(_(
                "Some login data is missing. If the problem persists, go to:\n"
                "Settings -> Login -> Advanced -> and click on RESET Everything."
            ))

            return

        deviceid = universe.generate_device_id(token=self.oauth_token)
        oauth = {'steamid': self.steamid, 'oauth_token': self.oauth_token}
        login_data = login.LoginData(auth={}, oauth=oauth)

        if not self._login_data or not self.sms_code:
            try:
                self._login_data = await self.application.webapi_session.add_authenticator(login_data, deviceid)
            except aiohttp.ClientError:
                self.status.error(_("Check your connection. (server down?)"))
            except webapi.AuthenticatorExists:
                self.status.error(_(
                    "There's already an authenticator active for that account.\n"
                    "Remove your current steam authenticator and try again."
                ))
            except webapi.PhoneNotRegistered:
                self.status.error(_(
                    "You must have a phone registered on your steam account to proceed.\n"
                    "Go to your Steam Account Settings, add a Phone Number, and try again."
                ))
            except NotImplementedError as exception:
                import sys, traceback
                utils.fatal_error_dialog(exception, traceback.print_tb(sys.exc_info), self.parent_window)
                self.application.on_exit_activate()
            else:
                self.status.info(_("Enter bellow the code received by SMS\nand click on 'Add Authenticator' button"))
                self.user_details_section.show_all()
                self.sms_code_item.set_text('')
                self.sms_code_item.grab_focus()
            finally:
                button.set_sensitive(True)
                return

        self.status.info(_("Adding authenticator"))

        try:
            await self.application.webapi_session.finalize_add_authenticator(
                self._login_data, self.sms_code, time_offset=self.application.time_offset,
            )
        except webapi.SMSCodeError:
            self.status.info(_("Invalid SMS Code. Please,\ncheck the code and try again."))
            self.user_details_section.show_all()
            self.sms_code_item.set_text('')
            self.sms_code_item.grab_focus()
        except aiohttp.ClientError:
            self.status.error(_("Check your connection. (server down?)"))
            self.user_details_section.show_all()
            self.sms_code_item.set_text('')
            self.sms_code_item.grab_focus()
        except Exception as exception:
            import sys, traceback
            utils.fatal_error_dialog(exception, traceback.print_tb(sys.exc_info), self.parent_window)
            self.application.on_exit_activate()
        else:
            self.status.info(_("Saving new secrets"))
            config.new("login", "shared_secret", self._login_data.auth['shared_secret'])
            config.new("login", "identity_secret", self._login_data.auth['identity_secret'])
            config.new("plugins", "steamguard", True)
            config.new("plguins", "confirmations", True)

            self.status.info(_(
                "RECOVERY CODE\n\n"
                "You will need this code to recovery your Steam Account\n"
                "if you lose access to STNG Authenticator. So, write"
                "down this recovery code.\n\n"
                "YOU WILL NOT ABLE TO VIEW IT AGAIN!\n"
            ))

            revocation_code = self._login_data.auth['revocation_code']

            self.add_authenticator_button.hide()

            revocation_status = utils.Status(6, _("Recovery Code"))
            revocation_status.set_pausable(False)
            revocation_status.set_display(revocation_code)
            revocation_status.set_status('')
            self.content_area.add(revocation_status)

            revocation_status.show_all()

            self.set_deletable(False)

            max_value = 30 * 3
            for offset in range(max_value):
                revocation_status.set_level(offset, max_value)
                await asyncio.sleep(0.3)

            self.set_deletable(True)
        finally:
            button.set_sensitive(True)
Exemple #20
0
    def _setButtonsSignals(self) -> None:
        """
        Set up the buttons and their respective signals for both grids.

        :param win: A window.
        :param fst_grid: The first grid container where the buttons goes in.
        :param box: The box container where the first grid goes in.
        :param fc_s: A list with file choosers.
        :return:
        """

        del_img: Optional[Pixbuf]

        img_path: str = path.abspath('asts/Icons/delete.png')

        try:
            del_img = Pixbuf().new_from_file_at_scale(img_path, 20, 20, False)
        except GLib_Error:
            exit(f'{img_path} file not found. Failed to create pixbuf.')

        icons: List[Optional[Image]] = [
            Image().new_from_pixbuf(del_img) for _ in range(4)
        ]

        btns: List[Button] = [Button() for _ in range(4)]

        for (idx, btn) in enumerate(btns):
            btn.set_image(icons[idx])
            setMargin(btn, 0, 5, 0, 5)
            btn.set_halign(Align.END)

            self._fst_grid.attach(btn, 2, idx, 1, 1)

        btns[FileType.ANKI2_COLLECTION].connect(
            'clicked',
            lambda _: self._fc_s[FileType.ANKI2_COLLECTION].unselect_all())

        btns[FileType.VIDEO].connect(
            'clicked', lambda _: self._fc_s[FileType.VIDEO].unselect_all())

        btns[FileType.SUBTITLE].connect(
            'clicked', lambda _: self._fc_s[FileType.SUBTITLE].unselect_all())

        btns[FileType.O_SUBTITLE].connect(
            'clicked',
            lambda _: self._fc_s[FileType.O_SUBTITLE].unselect_all())

        box: Box = Box()

        self._box.pack_end(box, False, True, 0)

        box.set_orientation(Orientation.HORIZONTAL)
        box.set_halign(Align.CENTER)

        cancel_btn: Button = Button(label='Cancel')

        box.pack_start(cancel_btn, False, True, 0)

        cancel_btn.set_margin_bottom(10)
        cancel_btn.connect('clicked', lambda _: self.close())

        self._next_btn = Button(label='Next')

        box.pack_end(self._next_btn, False, True, 0)

        setMargin(self._next_btn, 200, 10, 0, 0)
        self._next_btn.connect('clicked', self._onNextBtnClicked)

        timeout_add(300, self._setSensitiveNextBtn)
        timeout_add(300, self._checkInvalidSelection)
Exemple #21
0
class FilesChooser(Window):
    def __init__(self, app: Application):
        super().__init__(title='Asts', application=app)

        self._app: Application = app

        self.set_default_size(1000, 700)
        self.set_keep_above(True)
        self.set_resizable(False)

        self._box: Box = Box()
        self._box.set_orientation(Orientation.VERTICAL)

        setBgColor(widget=self, alpha=0.93)

        setMargin(self._box, 10)

        self._fst_grid: Grid = Grid()

        # labels
        self._setLabels()

        # file choosers button
        # _fc_s[0] = anki2.collection file
        # _fc_s[1] = video file
        # _fc_s[2] = subtitle file
        # _fc_s[3] = optional subtitle file
        self._fc_s: List[FileChooser] = self._setFileChoosers()

        # text entry
        self._entry: Entry
        self._setTextEntry()

        self._fillCachedFile()

        # filters
        self._setFilters()

        # buttons
        self._next_btn: Button
        self._setButtonsSignals()

        # box.pack_(child, expand, fill, padding)
        self._box.pack_start(self._fst_grid, False, True, 0)

        self.add(self._box)

    def _setLabels(self) -> None:
        """
        Setup the labels for the grid.

        :return:
        """

        labels: List[Label] = [
            Label(label='collection.anki2 File (Required):'),
            Label(label='Video (Required):'),
            Label(label='Subtitle File with The Target Language (Required):'),
            Label(label='Subtitle File with Translation (Optional):'),
            Label(label='Deck Name (Required):')
        ]

        for (idx, lbl) in enumerate(labels):
            lbl.set_halign(Align.START)

            # Grid.attach(child, left, top, width, height)
            self._fst_grid.attach(lbl, 0, idx, 1, 1)

    def _setFileChoosers(self) -> List[FileChooser]:
        """
        Set up the file choosers for the grid.

        :return: The file choosers created.
        """

        f_cs: List[FileChooser] = [FileChooserButton() for _ in range(4)]

        for (idx, f_c) in enumerate(f_cs):
            f_c.set_hexpand(True)
            setMargin(f_c, 10, 5, 10, 5)

            f_c.set_halign(Align.FILL)

            self._fst_grid.attach(f_c, 1, idx, 1, 1)

        return f_cs

    def _setFilters(self) -> None:
        """
        Set a filter for each file chooser.

        :return: 
        """

        ff1: FileFilter = FileFilter()
        ff1.set_name('collection.anki2')
        ff1.add_pattern('*.anki2')

        self._fc_s[FileType.ANKI2_COLLECTION].add_filter(ff1)

        ff2: FileFilter = FileFilter()
        ff2.set_name('Video File')
        ff2.add_mime_type('video/mp4')
        ff2.add_mime_type('video/wmv')
        ff2.add_mime_type('video/avi')
        ff2.add_mime_type('video/mkv')
        ff2.add_mime_type('video/webm')
        ff2.add_pattern('*.mp4')
        ff2.add_pattern('*.wmv')
        ff2.add_pattern('*.avi')
        ff2.add_pattern('*.mkv')
        ff2.add_pattern('*.webm')

        self._fc_s[FileType.VIDEO].add_filter(ff2)

        ff3: FileFilter = FileFilter()
        ff3.set_name('Subtitles (ASS/SRT)')
        ff3.add_pattern('*.srt')
        ff3.add_pattern('*.ass')

        self._fc_s[FileType.SUBTITLE].add_filter(ff3)
        self._fc_s[FileType.O_SUBTITLE].add_filter(ff3)

    def _fillCachedFile(self) -> None:
        """
        Fills up collection_file and deck_name filename.

        :return:
        """

        try:
            cache_dir: Filepath = path.abspath('data/cache')
            cached_usage: Filename = path.join(cache_dir + '/' +
                                               'cached_usage.txt')

            with open(cached_usage, 'r') as f:
                list_cache: List[str] = f.read().split('\n')
                self._fc_s[FileType.ANKI2_COLLECTION].set_filename(
                    list_cache[0])
                self._entry.set_text(list_cache[1])
        # it's safe to pass here
        # it means that there's no filename cached to be used
        except FileNotFoundError:
            pass

    def _setButtonsSignals(self) -> None:
        """
        Set up the buttons and their respective signals for both grids.

        :param win: A window.
        :param fst_grid: The first grid container where the buttons goes in.
        :param box: The box container where the first grid goes in.
        :param fc_s: A list with file choosers.
        :return:
        """

        del_img: Optional[Pixbuf]

        img_path: str = path.abspath('asts/Icons/delete.png')

        try:
            del_img = Pixbuf().new_from_file_at_scale(img_path, 20, 20, False)
        except GLib_Error:
            exit(f'{img_path} file not found. Failed to create pixbuf.')

        icons: List[Optional[Image]] = [
            Image().new_from_pixbuf(del_img) for _ in range(4)
        ]

        btns: List[Button] = [Button() for _ in range(4)]

        for (idx, btn) in enumerate(btns):
            btn.set_image(icons[idx])
            setMargin(btn, 0, 5, 0, 5)
            btn.set_halign(Align.END)

            self._fst_grid.attach(btn, 2, idx, 1, 1)

        btns[FileType.ANKI2_COLLECTION].connect(
            'clicked',
            lambda _: self._fc_s[FileType.ANKI2_COLLECTION].unselect_all())

        btns[FileType.VIDEO].connect(
            'clicked', lambda _: self._fc_s[FileType.VIDEO].unselect_all())

        btns[FileType.SUBTITLE].connect(
            'clicked', lambda _: self._fc_s[FileType.SUBTITLE].unselect_all())

        btns[FileType.O_SUBTITLE].connect(
            'clicked',
            lambda _: self._fc_s[FileType.O_SUBTITLE].unselect_all())

        box: Box = Box()

        self._box.pack_end(box, False, True, 0)

        box.set_orientation(Orientation.HORIZONTAL)
        box.set_halign(Align.CENTER)

        cancel_btn: Button = Button(label='Cancel')

        box.pack_start(cancel_btn, False, True, 0)

        cancel_btn.set_margin_bottom(10)
        cancel_btn.connect('clicked', lambda _: self.close())

        self._next_btn = Button(label='Next')

        box.pack_end(self._next_btn, False, True, 0)

        setMargin(self._next_btn, 200, 10, 0, 0)
        self._next_btn.connect('clicked', self._onNextBtnClicked)

        timeout_add(300, self._setSensitiveNextBtn)
        timeout_add(300, self._checkInvalidSelection)

    def _setTextEntry(self) -> None:
        """
        Sets the text entry for deck name.

        :return:
        """

        self._entry = Entry(placeholder_text='Deck name...')

        setMargin(self._entry, 10, 5, 10, 5)

        self._fst_grid.attach(self._entry, 1, 4, 1, 1)

    def _getFilename(self, f_type: FileType) -> Optional[str]:
        """
        Return the name of the file.

        :param f_type: The type of file.
        :return: The name of the file.
        """

        try:
            return self._fc_s[f_type].get_filename()
        except IndexError:
            return None

    def _getDeckName(self) -> str:
        """
        Gets the deck name.

        :return: The deck name.
        """

        return self._entry.get_text()

    def _checkInvalidSelection(self) -> bool:
        """
        Unselects any invalid filename selected through file choosers.

        :return: True to keep timeout_add running.
        """

        col: Optional[str] = self._getFilename(FileType.ANKI2_COLLECTION)
        vid: Optional[str] = self._getFilename(FileType.VIDEO)
        sub: Optional[str] = self._getFilename(FileType.SUBTITLE)
        o_sub: Optional[str] = self._getFilename(FileType.O_SUBTITLE)

        if col != None and not isCollection(col):
            self._fc_s[0].unselect_all()

        if vid != None and not isVideo(vid):
            self._fc_s[1].unselect_all()

        if sub != None and not isSub(sub):
            self._fc_s[2].unselect_all()

        if o_sub != None and not isSub(o_sub):
            self._fc_s[3].unselect_all()

        return True

    def _setSensitiveNextBtn(self) -> bool:
        """
        Set if a button is clickable or not.

        :return: True to keep timeout_add running.
        """

        col: bool = isCollection(self._getFilename(FileType.ANKI2_COLLECTION))
        vid: bool = isVideo(self._getFilename(FileType.VIDEO))
        sub: bool = isSub(self._getFilename(FileType.SUBTITLE))
        deck_name: str = self._getDeckName()

        if all((col, vid, sub, deck_name)):
            self._next_btn.set_sensitive(True)
        else:
            self._next_btn.set_sensitive(False)

        return True

    def _onNextBtnClicked(self, _) -> None:
        """
        Opens the generator of anki cards.

        :return:
        """

        createCacheDirIfItNotExists()

        clearCachedFiles()

        recentUsedFiles(self._getFilename(FileType.ANKI2_COLLECTION),
                        self._getDeckName())

        CardsGenerator(self, self._app,
                       self._getFilename(FileType.ANKI2_COLLECTION),
                       self._getFilename(FileType.VIDEO),
                       self._getFilename(FileType.SUBTITLE),
                       self._getFilename(FileType.O_SUBTITLE),
                       self._getDeckName()).showAll()
Exemple #22
0
def remove_tooltip(button: Gtk.Button):
    button.set_has_tooltip(False)
    return False
Exemple #23
0
 def on_save_clicked(self, button: Gtk.Button) -> None:
     serial_message = 'ms'
     self.application.send_serial(serial_message)
     button.set_label("Saved!")
Exemple #24
0
 def on_advanced_button_toggled(self, button: Gtk.Button) -> None:
     if button.get_active():
         advanced_settings = advanced.AdvancedSettingsDialog(
             self, self.application, button)
         advanced_settings.show_all()
Exemple #25
0
class CardsGenerator(Window):
    def __init__(self, parent: Window, app: Application,
                 col_filename: Filename, vid_filename: Filename,
                 sub_filename: Filename, opt_sub_filename: OptFilename,
                 deck_name: str):

        super().__init__(title='Asts - Anki Card Generator',
                         application=app,
                         transient_for=parent)

        self.set_default_size(width=1000, height=700)
        self.set_keep_above(True)
        self.set_modal(True)
        self.set_resizable(False)

        setBgColor(widget=self, alpha=0.93)

        self._main_box: Box = Box()
        self._main_box.set_orientation(Orientation.VERTICAL)
        setMargin(self._main_box, 10)

        self.add(self._main_box)

        self._subtitles_grid: Grid = Grid()
        setMargin(self._subtitles_grid, 5)

        # box.pack_(expand, fill, padding)
        self._main_box.pack_start(self._subtitles_grid, False, True, 0)

        self._collection_filename: Filename = col_filename
        self._video_filename: Filename = vid_filename
        self._subtitles_filename: Filename = sub_filename
        self._opt_subtitles_filename: OptFilename = opt_sub_filename
        self._deck_name: str = deck_name

        self._any_media_toggled: bool = False
        self._dict_any_media: Dict[str, bool]

        self._dict_any_change_front: Dict[str, bytes]
        self._dict_any_change_back: Dict[str, bytes]

        self._textview_front: TextView
        self._textview_back: TextView

        self._textbuffer_front: TextBuffer
        self._textbuffer_back: TextBuffer

        self._subtitles_liststore: ListStore
        self._subtitles_liststore_back: ListStore

        self._subtitles_treeview: TreeView

        self._selected_row: TreeSelection

        self._progress_bar: ProgressBar

        self._cancel_btn: Button
        self._generate_btn: Button

        self._cur_progress: int
        self._max_tasks: int

        self._cancel_task: bool

        self._list_of_sentences: ListSentences
        self._list_info_medias: List[List[Info]]

        self._color_tag_names: List[str]
        # TheadingHandler will utilize these
        # updating the status for each task tasks
        # also the sensitive and progress of the progress bar
        # depends on these.
        self._futures_list: List[Future]

    def showAll(self) -> None:
        """
        Draws the cards generator window and it's respective widgets.

        :return:
        """

        # subtitles tree view
        self._setSubtitleTreeView()

        # indice and dialogue cells
        self._setDialogCells()

        # start and end timer cells
        self._setTimerCells()

        # video, audio and image cells
        self._setMediasCells()

        # fills both tree view with the subtitles
        self._populateListStore()

        # setting the model after and initializing _selected_row and _dict_any_media
        # after the liststore being complete initialized
        self._subtitles_treeview.set_model(self._subtitles_liststore)

        self._selected_row = self._subtitles_treeview.get_selection()
        self._selected_row.connect('changed', self._itemSelected)

        self._dict_any_media = {
            str(key): False
            for key in enumerate(self._subtitles_liststore)
        }

        # search entry
        self._setSearchEntry()

        # sets up the sentence editing related (e.g toolbar, tagging, etc)
        self._setSentenceRelated()

        # all color tags are named as it's respective values
        self._color_tag_names = [
            '#9999c1c1f1f1',
            '#6262a0a0eaea',
            '#35358484e4e4',
            '#1c1c7171d8d8',
            '#1a1a5f5fb4b4',
            '#8f8ff0f0a4a4',
            '#5757e3e38989',
            '#3333d1d17a7a',
            '#2e2ec2c27e7e',
            '#2626a2a26969',
            '#f9f9f0f06b6b',
            '#f8f8e4e45c5c',
            '#f6f6d3d32d2d',
            '#f5f5c2c21111',
            '#e5e5a5a50a0a',
            '#ffffbebe6f6f',
            '#ffffa3a34848',
            '#ffff78780000',
            '#e6e661610000',
            '#c6c646460000',
            '#f6f661615151',
            '#eded33333b3b',
            '#e0e01b1b2424',
            '#c0c01c1c2828',
            '#a5a51d1d2d2d',
            '#dcdc8a8adddd',
            '#c0c06161cbcb',
            '#91914141acac',
            '#81813d3d9c9c',
            '#616135358383',
            '#cdcdabab8f8f',
            '#b5b583835a5a',
            '#98986a6a4444',
            '#86865e5e3c3c',
            '#636345452c2c',
            '#ffffffffffff',
            '#f6f6f5f5f4f4',
            '#dededddddada',
            '#c0c0bfbfbcbc',
            '#9a9a99999696',
            '#777776767b7b',
            '#5e5e5c5c6464',
            '#3d3d38384646',
            '#24241f1f3131',
            '#000000000000',
        ]

        # sets up dictionary used to track the tags used
        self._initDictionariesTag()

        # sets up the buttons to select all sentences
        self._setSelectAll()

        # sets up the progress bar
        self._setProgressBar()

        # cancel and generate buttonsj
        self._resetFuturesLists()
        self._setButtons()

        self.show_all()

    def _resetFuturesLists(self) -> None:
        """
        Assign a empty list of both lists of futures (futures_setences and futures_medias).

        :return:
        """

        self._futures_list = []

    def _setSearchEntry(self) -> None:
        """
        Connect the changed event for the search_entry object.

        :return:
        """

        search_entry: SearchEntry = SearchEntry()
        search_entry.set_halign(Align.END)

        setMargin(search_entry, 0, 5, 0, 5)

        self._subtitles_grid.attach(search_entry, 0, 0, 1, 1)

        search_entry.connect('changed', self.searchIt)

    def searchIt(self, search_entry: SearchEntry) -> None:
        """
        Searchs over the _subtitles_liststore.

        :return:
        """

        term_searched: str = search_entry.get_text()

        for i, term in enumerate(self._subtitles_liststore):
            if term_searched and term_searched in term[1].lower():
                self._subtitles_treeview.set_cursor(i)
                break

    def _setSelectAll(self) -> None:
        """
        Sets up widgets to select all sentences.

        :return:
        """

        grid: Grid = Grid()
        grid.set_halign(Align.END)
        self._subtitles_grid.attach(grid, 0, 2, 1, 1)

        lbl: Label = Label(label='Select all')
        setMargin(lbl, 5)

        grid.attach(lbl, 0, 0, 1, 1)

        all_vid_toggle: CheckButton = CheckButton()
        all_vid_toggle.set_halign(Align.CENTER)
        all_vid_toggle.connect('toggled', self._onAllVideosToggled)

        setMargin(all_vid_toggle, 5)

        grid.attach(all_vid_toggle, 1, 0, 1, 1)

        lbl2: Label = Label(label='Videos')

        setMargin(lbl2, 5)

        grid.attach(lbl2, 1, 1, 1, 1)

        all_audio_toggle: CheckButton = CheckButton()
        all_audio_toggle.set_halign(Align.CENTER)
        all_audio_toggle.connect('toggled', self._onAllAudiosToggled,
                                 all_vid_toggle)

        setMargin(all_audio_toggle, 5)

        grid.attach(all_audio_toggle, 2, 0, 1, 1)

        lbl3: Label = Label(label='Audios')

        setMargin(lbl3, 5)

        grid.attach(lbl3, 2, 1, 1, 1)

        all_img_toggle: CheckButton = CheckButton()
        all_img_toggle.set_halign(Align.CENTER)
        all_img_toggle.connect('toggled', self._onAllImagesToggled)

        setMargin(all_img_toggle, 5)

        grid.attach(all_img_toggle, 3, 0, 1, 1)

        lbl4: Label = Label(label='Snapshot')

        setMargin(lbl4, 5)

        grid.attach(lbl4, 3, 1, 1, 1)

    def _onAllVideosToggled(self, _) -> None:
        """
        Handle the toggled event for the ToggleButton object.

        :param widget: ToggleButton object.
        :return:
        """

        for i in range(len(self._subtitles_liststore)):
            if self._subtitles_liststore[i][5]:

                self._subtitles_liststore[i][
                    5] = not self._subtitles_liststore[i][5]
                self._subtitles_liststore[i][
                    4] = not self._subtitles_liststore[i][4]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][4]

            elif self._subtitles_liststore[i][6]:

                self._subtitles_liststore[i][
                    6] = not self._subtitles_liststore[i][6]
                self._subtitles_liststore[i][
                    4] = not self._subtitles_liststore[i][4]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][4]

            else:
                self._subtitles_liststore[i][
                    4] = not self._subtitles_liststore[i][4]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][4]

        if True in self._dict_any_media.values():
            self._any_media_toggled = True
        else:
            self._any_media_toggled = False

    def _onAllAudiosToggled(self, _) -> None:
        """
        Handle the toggled event for the ToggleButton object.

        :param widget: ToggleButton object.
        :return:
        """

        for i in range(len(self._subtitles_liststore)):
            if self._subtitles_liststore[i][4]:

                self._subtitles_liststore[i][
                    4] = not self._subtitles_liststore[i][4]
                self._subtitles_liststore[i][
                    5] = not self._subtitles_liststore[i][5]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][5]

            elif self._subtitles_liststore[i][5] and self._subtitles_liststore[
                    i][6]:

                self._subtitles_liststore[i][
                    5] = not self._subtitles_liststore[i][5]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][6]

            else:
                self._subtitles_liststore[i][
                    5] = not self._subtitles_liststore[i][5]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][5]

        if True in self._dict_any_media.values():
            self._any_media_toggled = True
        else:
            self._any_media_toggled = False

    def _onAllImagesToggled(self, _) -> None:
        """
        Handle the toggled event for the ToggleButton object.

        :param widget: ToggleButton object.
        :return:
        """

        for i in range(len(self._subtitles_liststore)):
            if self._subtitles_liststore[i][4]:

                self._subtitles_liststore[i][
                    4] = not self._subtitles_liststore[i][4]
                self._subtitles_liststore[i][
                    6] = not self._subtitles_liststore[i][6]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][6]

            else:
                self._subtitles_liststore[i][
                    6] = not self._subtitles_liststore[i][6]
                self._dict_any_media[str(i)] = self._subtitles_liststore[i][6]

        if True in self._dict_any_media.values():
            self._any_media_toggled = True
        else:
            self._any_media_toggled = False

    def _initDictionariesTag(self) -> None:
        """
        Init the default values for the used tags.

        :return:
        """

        # dictionaries to track the tags
        self._dict_any_change_front = ({
            str(key): serializeIt(text_buffer=self._textbuffer_front,
                                  tmp_string=value[1])
            for key, value in enumerate(self._subtitles_liststore)
        })

        self._dict_any_change_back = ({
            str(key): serializeIt(text_buffer=self._textbuffer_back,
                                  tmp_string=value[1])
            for key, value in enumerate(self._subtitles_liststore_back)
        })

    def _populateListStore(self) -> None:
        """
        Fills both list store (front and back) with subtitles.

        :return:
        """

        self._subtitles_liststore = ListStore(
            int,  # indice
            str,  # dialogue
            str,  # start timer
            str,  # end timer
            bool,  # whether video is selected
            bool,  # whether audio is selected
            bool  # whether image is selected
        )

        # only the first two values are important here
        self._subtitles_liststore_back = ListStore(int, str, str, str, bool,
                                                   bool, bool)

        dialogues_list: List[List[Info]] = extractAllDialogues(
            self._subtitles_filename)

        for dialogue in dialogues_list:
            self._subtitles_liststore.append(dialogue)

        if self._opt_subtitles_filename:
            opt_dialogues_list: List[List[Info]] = extractAllDialogues(
                self._opt_subtitles_filename)

            # the subtitles and their respective translations
            # may or may not be of same lenght
            # in that case fill the list with dummy values
            for i in range(len(dialogues_list)):
                try:
                    self._subtitles_liststore_back.append(
                        opt_dialogues_list[i])
                except IndexError:
                    self._subtitles_liststore_back.append(
                        (i, '', '', '', False, False, False))
        else:
            # in case no subtitles was selected for the back list store
            # fill it with dummy values
            for i in range(len(dialogues_list)):
                self._subtitles_liststore_back.append(
                    (i, '', '', '', False, False, False))

    def _setTimerCells(self) -> None:
        """
        Arrange the start and end timer cells.

        :return:
        """
        # Making some cells editable 'Start' and 'End' respectivily
        editable_start_field: CellRendererText = CellRendererText()
        editable_end_field: CellRendererText = CellRendererText()

        editable_start_field.set_property('editable', True)
        editable_end_field.set_property('editable', True)

        self._subtitles_treeview.append_column(
            TreeViewColumn(title='Start',
                           cell_renderer=editable_start_field,
                           text=2))

        self._subtitles_treeview.append_column(
            TreeViewColumn(title='End',
                           cell_renderer=editable_end_field,
                           text=3))

        editable_start_field.connect('edited', self._startFieldEdited)
        editable_end_field.connect('edited', self._endFieldEdited)

    def _startFieldEdited(self, _, path: TreePath, text: str) -> None:
        """
        Handle the edited event for the start timer field cell.

        :widget: CellRendererText object.
        :path: TreePath object.
        :text: A string to be assigned to subtitles_liststore.
        :return:
        """

        from re import compile, Pattern

        regex_timer: Pattern[str] = compile(
            r'([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9])')
        result = regex_timer.findall(text)

        if result:
            self._subtitles_liststore[path][2] = result[0]

    def _endFieldEdited(self, _, path: TreePath, text: str) -> None:
        """
        Handle the edited event for the end timer field cell.

        :widget: CellRendererText object.
        :path: TreePath object.
        :text: A string to be assigned to subtitles_liststore.
        :return:
        """

        from re import compile, Pattern

        regex_timer: Pattern[str] = compile(
            r'([0-9]?[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9])')
        result: List[str] = regex_timer.findall(text)

        if result:
            self._subtitles_liststore[path][3] = result[0]

    def _setDialogCells(self) -> None:
        """
        Arrange the dialogue and indice cell at the treeview.

        :return:
        """

        for i, title in enumerate(['Indice', 'Dialog']):
            renderer: CellRendererText = CellRendererText()
            path_column: TreeViewColumn = TreeViewColumn(
                title=title, cell_renderer=renderer, text=i)

            if title == 'Dialog':
                path_column.set_sizing(TreeViewColumnSizing.FIXED)
                path_column.set_fixed_width(520)
                path_column.set_min_width(520)
            self._subtitles_treeview.append_column(path_column)

    def _setMediasCells(self) -> None:
        """
        Arrange the video, audio and snapshot cells.

        :return:
        """

        # cell video, audio and snapshot to toggle
        renderer_video_toggle: CellRendererToggle = CellRendererToggle()
        column_toggle = TreeViewColumn(title='Video',
                                       cell_renderer=renderer_video_toggle,
                                       active=4)
        self._subtitles_treeview.append_column(column_toggle)
        renderer_video_toggle.connect("toggled", self._onCellVideoToggled)

        renderer_audio_toggle: CellRendererToggle = CellRendererToggle()
        column_toggle = TreeViewColumn(title='Audio',
                                       cell_renderer=renderer_audio_toggle,
                                       active=5)
        self._subtitles_treeview.append_column(column_toggle)
        renderer_audio_toggle.connect("toggled", self._onCellAudioToggled)

        renderer_snapshot_toggle: CellRendererToggle = CellRendererToggle()
        column_toggle = TreeViewColumn(title='Snapshot',
                                       cell_renderer=renderer_snapshot_toggle,
                                       active=6)
        self._subtitles_treeview.append_column(column_toggle)
        renderer_snapshot_toggle.connect("toggled", self._onCellImageToggled)

    def _onCellVideoToggled(self, _, path) -> None:
        """
        Handles the toggled event for the CellRendererToggle object.
        
        :param widget: CellRendererToggle object.
        :path path: TreePath object.
        :return:
        """

        if self._subtitles_liststore[path][5]:

            self._subtitles_liststore[path][
                5] = not self._subtitles_liststore[path][5]
            self._subtitles_liststore[path][
                4] = not self._subtitles_liststore[path][4]
            self._dict_any_media[path] = self._subtitles_liststore[path][4]

        elif self._subtitles_liststore[path][6]:

            self._subtitles_liststore[path][
                6] = not self._subtitles_liststore[path][6]
            self._subtitles_liststore[path][
                4] = not self._subtitles_liststore[path][4]
            self._dict_any_media[path] = self._subtitles_liststore[path][4]

        else:
            self._subtitles_liststore[path][
                4] = not self._subtitles_liststore[path][4]
            self._dict_any_media[path] = self._subtitles_liststore[path][4]

        if True in self._dict_any_media.values():
            self._any_media_toggled = True
        else:
            self._any_media_toggled = False

    def _onCellAudioToggled(self, _, path: str) -> None:
        """
        Handles the toggled event for the CellRendererToggle object.
        
        :param widget: CellRendererToggle object.
        :path path: TreePath object.
        :return:
        """

        if self._subtitles_liststore[path][4]:

            self._subtitles_liststore[path][
                4] = not self._subtitles_liststore[path][4]
            self._subtitles_liststore[path][
                5] = not self._subtitles_liststore[path][5]
            self._dict_any_media[path] = self._subtitles_liststore[path][5]

        elif self._subtitles_liststore[path][5] and self._subtitles_liststore[
                path][6]:

            self._subtitles_liststore[path][
                5] = not self._subtitles_liststore[path][5]
            self._dict_any_media[path] = self._subtitles_liststore[path][6]

        else:
            self._subtitles_liststore[path][
                5] = not self._subtitles_liststore[path][5]
            self._dict_any_media[path] = self._subtitles_liststore[path][5]

        if True in self._dict_any_media.values():
            self._any_media_toggled = True
        else:
            self._any_media_toggled = False

    def _onCellImageToggled(self, _, path: str) -> None:
        """
        Handles the toggled event for the CellRendererToggle object.
        
        :param widget: CellRendererToggle object.
        :path path: TreePath object.
        :return:
        """

        if self._subtitles_liststore[path][4]:

            self._subtitles_liststore[path][
                4] = not self._subtitles_liststore[path][4]
            self._subtitles_liststore[path][
                6] = not self._subtitles_liststore[path][6]
            self._dict_any_media[path] = self._subtitles_liststore[path][6]

        elif self._subtitles_liststore[path][6] and self._subtitles_liststore[
                path][5]:

            self._subtitles_liststore[path][
                6] = not self._subtitles_liststore[path][6]
            self._dict_any_media[path] = self._subtitles_liststore[path][5]

        else:
            self._subtitles_liststore[path][
                6] = not self._subtitles_liststore[path][6]
            self._dict_any_media[path] = self._subtitles_liststore[path][6]

        if True in self._dict_any_media.values():
            self._any_media_toggled = True
        else:
            self._any_media_toggled = False

    def _setSubtitleTreeView(self) -> None:
        """
        Sets the scrolled window and a tree view for subtitles info.

        :return:
        """

        self._subtitles_treeview = TreeView()
        self._subtitles_treeview.set_grid_lines(TreeViewGridLines.BOTH)

        scrl_wnd: ScrolledWindow = ScrolledWindow()
        scrl_wnd.set_hexpand(True)
        scrl_wnd.set_vexpand(True)

        scrl_wnd.add(self._subtitles_treeview)

        self._subtitles_grid.attach(scrl_wnd, 0, 1, 1, 1)

    def _itemSelected(self, _) -> None:
        """
        Keeps tracks of selections change at the treeview object.

        :return:
        """

        path: str = self._selected_row.get_selected_rows()[1][0].to_string()

        deserializeIt(self._textbuffer_front,
                      self._dict_any_change_front[path])
        deserializeIt(self._textbuffer_back, self._dict_any_change_back[path])

        self._textbuffer_front.connect('changed', self._editingCard)
        self._textbuffer_back.connect('changed', self._editingCardBack)

    def _editingCard(self, textbuffer_front: TextBuffer) -> None:
        """
        Keeps track of changes at the text_buffer_front.

        :param text_buffer_front: TextBuffer object.
        :return:
        """

        path: TreePath = self._selected_row.get_selected_rows()[1][0]
        start_iter_front: TextIter = textbuffer_front.get_start_iter()
        end_iter_front: TextIter = textbuffer_front.get_end_iter()
        self._subtitles_liststore[path][1] = textbuffer_front.get_text(
            start_iter_front, end_iter_front, True)

        self._dict_any_change_front[path.to_string()] = serializeIt(
            text_buffer=textbuffer_front)

    def _editingCardBack(self, textbuffer_back: TextBuffer) -> None:
        """
        Keeps track of changes at the text_buffer_back.

        :param text_buffer_back: TextBuffer object.
        :return:
        """

        path: TreePath = self._selected_row.get_selected_rows()[1][0]
        start_iter_back: TextIter = textbuffer_back.get_start_iter()
        end_iter_back: TextIter = textbuffer_back.get_end_iter()
        self._subtitles_liststore_back[path][1] = textbuffer_back.get_text(
            start_iter_back, end_iter_back, True)

        self._dict_any_change_back[path.to_string()] = serializeIt(
            text_buffer=textbuffer_back)

    def _setSentenceRelated(self) -> None:
        """
        Sets up the sentence editing widgets related.
        Also initialize both text buffers.

        :return:
        """

        box: Box = Box()

        self._main_box.pack_start(box, False, True, 0)

        box.set_orientation(Orientation.VERTICAL)

        setMargin(box, 5)

        toolbar: Toolbar = Toolbar()

        box.pack_start(toolbar, False, True, 0)

        toolbar.set_halign(Align.END)
        setMargin(toolbar, 5)

        lbl: Label = Label()
        lbl.set_markup('<i><b>Front</b></i>')

        box.pack_start(lbl, False, True, 0)

        lbl.set_halign(Align.START)
        setMargin(lbl, 5)

        scrl_wnd: ScrolledWindow = ScrolledWindow()
        scrl_wnd.set_hexpand(True)
        scrl_wnd.set_vexpand(True)

        textview: TextView = TextView()
        scrl_wnd.add(textview)

        box.pack_start(scrl_wnd, False, True, 0)

        self._textbuffer_front = textview.get_buffer()

        lbl2: Label = Label()
        lbl2.set_halign(Align.START)
        lbl2.set_markup('<i><b>Back</b></i>')

        box.pack_start(lbl2, False, True, 0)
        setMargin(lbl2, 5)

        scrl_wnd2: ScrolledWindow = ScrolledWindow()
        scrl_wnd2.set_hexpand(True)
        scrl_wnd2.set_vexpand(True)

        textview2: TextView = TextView()
        scrl_wnd2.add(textview2)

        box.pack_end(scrl_wnd2, False, True, 0)

        self._textbuffer_back = textview2.get_buffer()

        # this depends on the text buffer to be initialized
        self._setToolbarColorButton(toolbar)

        toolbar.insert(SeparatorToolItem(), 3)

        self._setToolbarUnderlineButton(toolbar)
        self._setToolbarBoldButton(toolbar)
        self._setToolbarItalicButton(toolbar)

        toolbar.insert(SeparatorToolItem(), 7)

        self._setToolbarTagRemoverButton(toolbar)

    def _setToolbarColorButton(self, toolbar: Toolbar) -> None:
        """
        Sets up the color button from the toolbar.

        :param toolbar: Toolbar object
        :return:
        """

        set_color_button: ToolButton = ToolButton()
        set_color_button.set_icon_name('gtk-select-color')
        toolbar.insert(set_color_button, 1)

        tool_item_color_button: ToolItem = ToolItem()
        color_button = ColorButton()

        tool_item_color_button.add(color_button)
        toolbar.insert(tool_item_color_button, 2)

        set_color_button.connect('clicked', self._onToolbarColorBtnClicked,
                                 color_button)

    def _setToolbarUnderlineButton(self, toolbar: Toolbar) -> None:
        """
        Sets up the underline button from the toolbar.

        :param toolbar: Toolbar object
        :return:
        """

        tag_underline_front: TextTag = self._textbuffer_front.create_tag(
            'underline', underline=Underline.SINGLE)
        tag_underline_back: TextTag = self._textbuffer_back.create_tag(
            'underline', underline=Underline.SINGLE)
        button_underline: ToolButton = ToolButton()

        button_underline.set_icon_name('format-text-underline-symbolic')
        toolbar.insert(button_underline, 4)

        button_underline.connect('clicked', self._onToolbarTagBtnClicked,
                                 tag_underline_front, tag_underline_back)

    def _setToolbarBoldButton(self, toolbar: Toolbar) -> None:
        """
        Sets up the bold button from the toolbar.

        :param toolbar: Toolbar object
        :return:
        """

        tag_bold_front: TextTag = self._textbuffer_front.create_tag(
            'bold', weight=Weight.BOLD)
        tag_bold_back: TextTag = self._textbuffer_back.create_tag(
            'bold', weight=Weight.BOLD)
        button_bold: ToolButton = ToolButton()

        button_bold.set_icon_name('format-text-bold-symbolic')
        toolbar.insert(button_bold, 5)

        button_bold.connect('clicked', self._onToolbarTagBtnClicked,
                            tag_bold_front, tag_bold_back)

    def _setToolbarItalicButton(self, toolbar: Toolbar) -> None:
        """
        Sets up the italic button from the toolbar.

        :param toolbar: Toolbar object
        :return:
        """

        tag_italic_front: TextTag = self._textbuffer_front.create_tag(
            'italic', style=Style.ITALIC)
        tag_italic_back: TextTag = self._textbuffer_back.create_tag(
            'italic', style=Style.ITALIC)

        button_italic: ToolButton = ToolButton()
        button_italic.set_icon_name('format-text-italic-symbolic')
        toolbar.insert(button_italic, 6)

        button_italic.connect('clicked', self._onToolbarTagBtnClicked,
                              tag_italic_front, tag_italic_back)

    def _setToolbarTagRemoverButton(self, toolbar: Toolbar) -> None:
        """
        Sets up the tag remover button from the toolbar.

        :param toolbar: Toolbar object.
        :return:
        """

        button_remove_all_tags: ToolButton = ToolButton()

        button_remove_all_tags.set_icon_name('edit-clear-symbolic')
        toolbar.insert(button_remove_all_tags, 8)

        button_remove_all_tags.connect(
            'clicked', lambda _: self._removeAllTagsFromSelection())

    def _getBounds(self) -> Tuple[TextMark, TextMark, Optional[str]]:
        """
        Returns the selection of the text in the text buffer.

        :return: A tuple with the textiter of the selection and the path string.
        """

        path: Optional[str]

        # if no row is selected
        # a IndexError will be raised
        try:
            path = self._selected_row.get_selected_rows()[1][0].to_string()
        except IndexError:
            path = None

        bounds_front: TextMark = self._textbuffer_front.get_selection_bounds()
        bounds_back: TextMark = self._textbuffer_back.get_selection_bounds()

        return (bounds_front, bounds_back, path)

    def _onToolbarColorBtnClicked(self, _, color_button: ColorButton) -> None:
        """
        Handles the clicked event for the tool_item_color_button.

        :param set_color_button: ToolButton object.
        :param color_button: ColorButton object.
        :return:
        """

        start: TextIter
        end: TextIter
        bounds_front: TextMark
        bounds_back: TextMark
        path: Optional[str]

        color: str = color_button.get_color().to_string()

        tag_table_front: TextTagTable = self._textbuffer_front.get_tag_table()
        tag_table_back: TextTagTable = self._textbuffer_back.get_tag_table()

        (bounds_front, bounds_back, path) = self._getBounds()

        # no selected row so there's nothing to do
        if not path:
            return

        ##### FRONT
        if bounds_front:
            (start, end) = bounds_front

            # only the first color applied to the selection
            # will be present at the final card
            # so remove all color previously applied to the current selected text.
            self._removeAllTagsFromSelection(color_tags=True)

            if not tag_table_front.lookup(color):
                tag_front: TextTag = self._textbuffer_front.create_tag(
                    color, foreground=color)
                self._textbuffer_front.apply_tag(tag_front, start, end)
            else:
                self._textbuffer_front.apply_tag_by_name(color, start, end)

            self._dict_any_change_front[path] = serializeIt(
                text_buffer=self._textbuffer_front)

        ###### BACK
        if bounds_back:
            (start, end) = bounds_back

            # only the first color applied to the selected text
            # will be present at the final card
            # so remove all color previously applied to the current selected text.
            self._removeAllTagsFromSelection(color_tags=True)

            if not tag_table_back.lookup(color):
                tag_back = self._textbuffer_back.create_tag(color,
                                                            foreground=color)
                self._textbuffer_back.apply_tag(tag_back, start, end)
            else:
                self._textbuffer_back.apply_tag_by_name(color, start, end)

            self._dict_any_change_back[path] = serializeIt(
                text_buffer=self._textbuffer_back)

    def _onToolbarTagBtnClicked(self, _, tag_front: TextTag,
                                tag_back: TextTag) -> None:
        """
        Handles the clicked event for the tool button. 

        :param widget: ToolButton object.
        :param tag_front: TextTag object.
        :param tag_back: TextTag object.
        :return:
        """

        start: TextIter
        end: TextIter
        bounds_front: TextMark
        bounds_back: TextMark
        path: Optional[str]

        (bounds_front, bounds_back, path) = self._getBounds()

        # no selected row so there's nothing to do
        if not path:
            return

        ##### FRONT
        if bounds_front:
            (start, end) = bounds_front

            self._textbuffer_front.apply_tag(tag_front, start, end)

            self._dict_any_change_front[path] = serializeIt(
                text_buffer=self._textbuffer_front)

        ###### BACK
        if bounds_back:
            (start, end) = bounds_back
            self._textbuffer_back.apply_tag(tag_back, start, end)

            self._dict_any_change_back[path] = serializeIt(
                text_buffer=self._textbuffer_back)

    def _removeAllTagsFromSelection(self, color_tags: bool = False) -> None:
        """
        Remove all tags from the current selected text.

        :param color_tags: If true only removes color tags.
        :return:
        """

        start: TextIter
        end: TextIter
        bounds_front: TextMark
        bounds_back: TextMark
        path: Optional[str]

        tag_table_front: TextTagTable = self._textbuffer_front.get_tag_table()
        tag_table_back: TextTagTable = self._textbuffer_back.get_tag_table()

        (bounds_front, bounds_back, path) = self._getBounds()

        # no selected row so there's nothing to do
        if not path:
            return

        ### FRONT
        if bounds_front:
            (start, end) = bounds_front

            if color_tags:
                for c in self._color_tag_names:
                    if tag_table_front.lookup(c):
                        self._textbuffer_front.remove_tag_by_name(
                            c, start, end)
            else:
                self._textbuffer_front.remove_all_tags(start, end)

            self._dict_any_change_front[path] = serializeIt(
                text_buffer=self._textbuffer_front)

        ### BACK
        if bounds_back:
            (start, end) = bounds_back

            if color_tags:
                for c in self._color_tag_names:
                    if tag_table_back.lookup(c):
                        self._textbuffer_back.remove_tag_by_name(c, start, end)
            else:
                self._textbuffer_back.remove_all_tags(start, end)

            self._dict_any_change_back[path] = serializeIt(
                text_buffer=self._textbuffer_back)

    def _setProgressBar(self) -> None:
        """
        Sets up the progress bar.

        :return:
        """

        self._cur_progress = 0

        self._progress_bar = ProgressBar()

        setMargin(self._progress_bar, 5)

        self._main_box.pack_start(self._progress_bar, False, True, 0)

    def _setButtons(self) -> None:
        """
        Sets up the cancel and generate buttons.

        :return:
        """

        box: Box = Box()

        self._main_box.pack_end(box, False, True, 0)

        box.set_halign(Align.CENTER)
        box.set_orientation(Orientation.HORIZONTAL)

        setMargin(box, 5)

        self._cancel_btn = Button(label='Cancel')

        box.pack_start(self._cancel_btn, False, True, 0)

        setMargin(self._cancel_btn, 5, 5, 100, 5)
        self._cancel_btn.connect('clicked', self._onCancelBtnClicked)

        self._generate_btn = Button(label='Generate')

        box.pack_end(self._generate_btn, False, True, 0)

        setMargin(self._generate_btn, 100, 5, 5, 5)
        self._generate_btn.connect('clicked', self._onGenerateBtnClicked)

        timeout_add(300, self._setSensitiveGenerateBtn)

    def _setSensitiveGenerateBtn(self) -> bool:
        """
        Set the senstive for the generate_btn.

        :return: A boolean to signal whether idle_add should remove it from list event.
        """

        if self._cur_progress or not self._allFuturesDone():
            self._generate_btn.set_sensitive(False)
        elif not self._any_media_toggled:
            self._generate_btn.set_sensitive(False)
        else:
            self._generate_btn.set_sensitive(True)

        return True

    def _allFuturesDone(self) -> bool:
        """
        Check for the status of futures.

        :return: Return true if all futures are done.
        """

        for f in self._futures_list:
            if not f.done(): return False

        return True

    def _updateProgress(self) -> bool:
        """
        Keep track of the objects yet to be completed.
        Updates the progress bar.
        
        :param future: Parameter passed by add_done_callback.
        :return: a boolean to signal whether idle_add should remove it from list event.
        """

        if not self.getCancelTaskStatus():
            self._cur_progress += 1
            self._progress_bar.set_fraction(self._cur_progress /
                                            self._max_tasks)
            self._progress_bar.set_text(None)
            self._progress_bar.set_show_text(True)

            if self._cur_progress == self._max_tasks:
                self._cur_progress = 0
                self._progress_bar.set_text('Done!')
                self._progress_bar.set_show_text(True)

        return False

    def resetProgressbar(self) -> None:
        """
        Resets the progress bar back to zero.

        :return:
        """

        self._cur_progress = 0
        self._progress_bar.set_fraction(self._cur_progress)
        self._progress_bar.set_show_text(False)

    def idleaddUpdateProgress(self, _) -> None:
        """
        Call idle_add to call updateProgress.
        
        :param future: Optional future object.
        :return:
        """

        idle_add(self._updateProgress)

    def getCancelTaskStatus(self) -> bool:
        """
        Get the status for the cancel_task.

        :return: Return true if the task should be cancelled.
        """

        return self._cancel_task

    def setCancelTaskStatus(self, status: bool) -> None:
        """
        Set the status for the cancel_task.

        :return:
        """

        self._cancel_task = status

    def _idleaddUpdateProgress(self, _) -> None:
        """
        Call idle_add to call updateProgress.
        
        :param future: Optional future object.
        :return:
        """

        idle_add(self._updateProgress)

    def _setSensitiveCancelBtn(self) -> bool:
        """
        Set the sensitive for snd_cancel_button.

        :return:
        """

        if self._allFuturesDone():
            self._progress_bar.set_text('Canceled!')

            self._cancel_btn.set_sensitive(True)

            return False
        else:
            self._progress_bar.set_text('Cancelling please wait...')
            self._cancel_btn.set_sensitive(False)

        return True

    def _onCancelBtnClicked(self, _) -> None:
        """
        Handle the clicked event for the second_cancel_button button.

        :param widget: Button object.
        :return:
        """

        if not self._cur_progress:
            self._generate_btn.set_sensitive(True)
            self.close()
        else:
            self.setCancelTaskStatus(True)

            self._cur_progress = 0

            self._progress_bar.set_fraction(self._cur_progress)
            self._progress_bar.set_show_text(True)

            timeout_add(300, self._setSensitiveCancelBtn)

        self._cur_progress = 0
        self._progress_bar.set_fraction(self._cur_progress)

    def _onGenerateBtnClicked(self, _) -> None:
        """
        Handle the click event for the generate_btn.

        :return:
        """

        from asts.Threading import ThreadingHandler

        self._listMediasSentences()

        ThreadingHandler(self)

    def _listMediasSentences(self) -> None:
        """
        Create two lists and fill them with filenames and sentences.

        :return:
        """

        from uuid import uuid1

        from asts.Utils import PangoToHtml

        # case other tasks already had been scheduled
        self._resetFuturesLists()

        self._list_of_sentences = []
        self._list_info_medias = []

        p: PangoToHtml = PangoToHtml()

        for i in range(len(self._subtitles_liststore)):
            if self._subtitles_liststore[i][4] or self._subtitles_liststore[i][
                    5] or self._subtitles_liststore[i][6]:
                # a unique id for each media, some images will conflict if it has the same name as a image
                # on anki media collection
                uuid_media = uuid1().int

                text_front: str = p.feed(self._dict_any_change_front[str(i)])
                text_back: str = p.feed(self._dict_any_change_back[str(i)])

                self._list_info_medias.append(
                    [str(uuid_media)] + (self._subtitles_liststore[i][1:]))

                if self._subtitles_liststore[i][
                        4] and not self._subtitles_liststore[i][6]:
                    self._list_of_sentences.append(
                        (text_front, text_back, f'{uuid_media}.mp4', None,
                         None))
                elif self._subtitles_liststore[i][
                        5] and self._subtitles_liststore[i][6]:
                    self._list_of_sentences.append(
                        (text_front, text_back, None, f'{uuid_media}.mp3',
                         f'{uuid_media}.bmp'))
                elif self._subtitles_liststore[i][
                        5] and not self._subtitles_liststore[i][6]:
                    self._list_of_sentences.append(
                        (text_front, text_back, None, f'{uuid_media}.mp3',
                         None))
                else:
                    self._list_of_sentences.append(
                        (text_front, text_back, None, None,
                         f'{uuid_media}.bmp'))

        self._max_tasks = len(self._list_info_medias) + len(
            self._list_of_sentences)

    def getCollection(self) -> Filename:
        """
        Returns the filename for the anki2.collection.

        :return: Filename of the anki2.collection.
        """

        return self._collection_filename

    def getDeckName(self) -> str:
        """
        Returns the deck name.

        :return: Deck name.
        """

        return self._deck_name

    def getVideoFilename(self) -> Filename:
        """
        Returns the name of the video file.

        :return: Video filename.
        """

        return self._video_filename

    def getListInfoMedias(self) -> List[List[Info]]:
        """
        Returns a list with information about each media to be used at creating cards.

        :return: A list with information about each media.
        """

        return self._list_info_medias

    def getListOfSentences(self) -> ListSentences:
        """
        Returns a List with information about each sentence to be used at creating cards.

        :return: A list with information about each sentence.
        """

        return self._list_of_sentences

    def appendFuture(self, future: Future) -> None:
        """
        Append the future to _futures_list.

        :return:
        """

        self._futures_list.append(future)
    def on_selection_changed(self, icon_view, album=None):
        popup = Popover.new(self.albumview)
        popup.set_size_request(810, 240)

        if album is None:
            selection = icon_view.get_selected_items()
            if len(selection) != 1:
                return

            path = selection[0]
            treeiter = self.albumfilter.get_iter(path)

            isset, path, cell = icon_view.get_cursor()
            isset, rect = icon_view.get_cell_rect(path, cell)
            popup.set_pointing_to(rect)

            album_id = self.albumfilter.get_value(treeiter, 4)
            album_obj = self.albums[album_id]
        else:
            album_obj = album
            popup.set_relative_to(self.search_entry)

        # Handle double clicks
        def empty_dblclick():
            self.dblclick = None

        if self.dblclick is None:
            self.dblclick = album_obj
            timeout_add(1000, empty_dblclick)
        elif self.dblclick == album_obj:
            self.play(album_obj)
            return

        album = album_obj.name
        artist = album_obj.artist

        glade_album = join(self.functions.datadir, 'glade', 'albumview.ui')
        box = gtk_builder()
        box.set_translation_domain('bluemindo')
        box.add_from_file(glade_album)
        popup.add(box.get_object('box1'))

        box.get_object('label_album').set_text(album)
        box.get_object('label_artist').set_text(artist)

        bdir = join(self.userconf.datadir, 'modules', 'player', 'covers')
        cover = join(bdir, self.functions.get_hash(album, artist))
        if isfile(cover):
            cover_px = Pixbuf.new_from_file_at_scale(cover, 180, 180, True)
        else:
            cover_px = Pixbuf.new_from_file(join(self.functions.datadir,
                                            'image', 'logo_head_big.png'))

        box.get_object('album_cover').set_from_pixbuf(cover_px)

        def play_album(wdg, album):
            self.play(album)

        def queue_album(wdg, album):
            self.queue(album)

        def change_cover(wdg, ka, album):
            artist_name = album.artist
            album_name = album.name

            fcdialog = FileChooserDialog(
                        title=_('Change the cover picture for this album'),
                        buttons=(_('Select'), ResponseType.OK))

            fcdialog.set_transient_for(self.widgets[0][11])
            response = fcdialog.run()
            if response == ResponseType.OK:
                filename = fcdialog.get_filename()

                datadir = self.userconf.datadir
                hash_a = self.functions.get_hash(album_name, artist_name)
                pictures_dir = join(datadir, 'modules', 'player', 'covers')
                album_file = join(pictures_dir, hash_a)

                copyfile(filename, album_file)

                new = Pixbuf.new_from_file_at_scale(album_file, 180, 180, True)
                box.get_object('album_cover').set_from_pixbuf(new)

            fcdialog.destroy()

        box.get_object('button_play').connect('clicked', play_album, album_obj)

        box.get_object('button_add').connect('clicked', queue_album, album_obj)

        box.get_object('coverevent').connect('button-press-event',
                                             change_cover, album_obj)

        i = 0
        a = -1
        previous_column = 0

        grid_songs = box.get_object('grid_songs')
        grid_songs.set_size_request(-1, 200)
        grid_songs.set_column_spacing(5)

        try:
            kids = grid_songs.get_children()
            for kid in kids:
                grid_songs.remove(kid)
        except IndexError:
            pass

        for song in album_obj.tracks:
            i += 1
            a += 1

            def queue(wdg, song):
                self.queue(song)

            def play(wdg, song):
                self.play(song)

            song_wdg = Box(spacing=0)
            song_btr = Button()
            song_btr.connect('clicked', play, song)
            song_btr.set_relief(ReliefStyle.NONE)
            song_btr_content = Box(spacing=0)
            song_btr.add(song_btr_content)

            song_tr = Label()
            song_tr.set_markup('<span foreground="grey">' + str(song.track)
                               + '</span>')
            song_tr.set_width_chars(3)
            song_btr_content.pack_start(song_tr, False, True, 0)
            song_ti = Label()
            song_ti.set_markup('<b>' + self.functions.view_encode(song.title, 22)
                               + '</b>')
            song_ti.set_alignment(0.0, 0.5)
            song_ti.set_size_request(190, -1)
            song_btr_content.pack_start(song_ti, False, False, 0)

            length = self.functions.human_length(song.length)
            song_le = Label()
            song_le.set_markup('<span foreground="grey">' + length
                               + '</span>')
            song_le.set_width_chars(5)
            song_btr_content.pack_start(song_le, False, True, 0)

            song_wdg.pack_start(song_btr, False, False, 0)

            song_add = Button.new_from_icon_name('list-add-symbolic', 0)
            song_add.set_property('relief', 2)
            song_add.set_size_request(14, 14)
            song_add.connect('clicked', queue, song)
            song_wdg.pack_start(song_add, False, False, 0)

            if i <= len(album_obj.tracks)/2:
                column = 0
                previous_column = 0
                row = a
            else:
                if previous_column == 0:
                    a = 0
                column = 1
                previous_column = 1
                row = a

            grid_songs.attach(song_wdg, column, row, 1, 1)
        popup.show_all()
    def __init__(self, extensions):
        # Start threads
        threads_init()

        self.extensions = extensions

        # Create the main Bluemindo window
        self.main_window = Window()
        functions.open_bluemindo(self.main_window)

        # Handling close button
        def close_window(wdg, ka):
            functions.close_bluemindo(self.main_window, True)

        self.main_window.connect('delete_event', close_window)

        # Create the whole Header Bar
        box = HeaderBar()
        box.set_show_close_button(True)
        box.props.title = 'Bluemindo'
        self.main_window.set_titlebar(box)

        # Add an icon to the window
        icon_file = join(functions.datadir, 'image', 'logo_head_small.png')
        pixbuf = Pixbuf.new_from_file(icon_file)
        self.main_window.set_icon(pixbuf)

        # Add the about button
        about_button = Button(relief=2)
        about_button.add(
            Image.new_from_gicon(ThemedIcon(name='help-about-symbolic'),
                                 IconSize.BUTTON))
        box.pack_end(about_button)

        # Add the reload button
        refresh_button = Button(relief=2)
        refresh_button.add(
            Image.new_from_gicon(ThemedIcon(name='view-refresh-symbolic'),
                                 IconSize.BUTTON))
        box.pack_end(refresh_button)

        # Add PREVIOUS/STOP/PLAYPAUSE/NEXT buttons
        player_box = Box(orientation=Orientation.HORIZONTAL)
        StyleContext.add_class(player_box.get_style_context(), 'linked')

        previous_b = Button()
        previous_b.set_size_request(42, -1)
        previous_b.add(
            Image.new_from_gicon(
                ThemedIcon(name='media-skip-backward-symbolic'),
                IconSize.BUTTON))
        player_box.add(previous_b)

        stop_b = Button()
        stop_b.set_size_request(42, -1)
        stop_b.add(
            Image.new_from_gicon(
                ThemedIcon(name='media-playback-stop-symbolic'),
                IconSize.BUTTON))
        player_box.add(stop_b)

        playpause_b = Button()
        playpause_b.set_size_request(55, -1)
        playpause_b.add(
            Image.new_from_gicon(
                ThemedIcon(name='media-playback-start-symbolic'),
                IconSize.BUTTON))
        player_box.add(playpause_b)

        next_b = Button()
        next_b.set_size_request(42, -1)
        next_b.add(
            Image.new_from_gicon(
                ThemedIcon(name='media-skip-forward-symbolic'),
                IconSize.BUTTON))
        player_box.add(next_b)

        box.pack_start(player_box)

        # Create the main window
        glade_main = join(functions.datadir, 'glade', 'mainwindow.ui')
        win = gtk_builder()
        win.set_translation_domain('bluemindo')
        win.add_from_file(glade_main)

        self.main_window.add(win.get_object('box1'))

        # Connect to the about button
        def show_dialog(wdg):
            dialog = AboutDialog()
            dialog.set_transient_for(self.main_window)

            dialog.set_artists(['Thomas Julien <*****@*****.**>'])
            dialog.set_authors([
                'Erwan Briand <*****@*****.**>',
                'Vincent Berset <*****@*****.**>',
                'Thibaut Girka <*****@*****.**>',
                'Ľubomír Remák <*****@*****.**>',
                'Anaël Verrier <*****@*****.**>'
            ])
            dialog.set_translator_credits(
                'Bruno Conde <*****@*****.**>\n' +
                'Niklas Grahn <*****@*****.**>\n' +
                'Ľubomír Remák <*****@*****.**>\n' +
                'Salvatore Tomarchio <*****@*****.**>\n' +
                'Shang Yuanchun <*****@*****.**>')

            dialog.set_copyright('Copyright © 2007-2016 Erwan Briand ' +
                                 '<*****@*****.**>')

            dialog.set_comments(
                _('Ergonomic and modern music player ' +
                  'designed for audiophiles.'))

            dialog.set_license('GNU General Public License (v3)')
            dialog.set_license_type(10)

            dialog.set_program_name('Bluemindo')
            dialog.set_version('1.0RC1')
            dialog.set_website('http://bluemindo.codingteam.net')

            pxbf = Pixbuf.new_from_file_at_scale(
                join(functions.datadir, 'image', 'logo_head_big.png'), 60, 60,
                True)
            dialog.set_logo(pxbf)

            dialog.show_all()

        about_button.connect('clicked', show_dialog)

        # Start main handler
        headerbar_wdg = [
            box, None, about_button, refresh_button, player_box, previous_b,
            stop_b, playpause_b, next_b, None,
            win.get_object('box1'), self.main_window
        ]
        self.wdg = [headerbar_wdg, win]
Exemple #28
0
 def get_string_from_button(button: Gtk.Button) -> str:
     """
     Returns the displayed string from a button
     :return: the button string
     """
     return button.get_label()