Ejemplo n.º 1
0
def combos_config(datos_conexion, objeto, tabla, cod):
    if tabla == "ajustemotivos":
        lista = ListStore(int, str, int)
    elif tabla == "impuestos":
        lista = ListStore(int, str, float)
    elif tabla == "monedas_s":
        lista = ListStore(int, str, int, str, str)
    elif tabla == "turnos":
        lista = ListStore(int, str, str, str)
    else:
        tipo = str if tabla in ("generos", "tipodocumentos",
                                "unidadmedidas") else int
        lista = ListStore(tipo, str)
    objeto.set_model(lista)

    cell = CellRendererText()
    objeto.pack_start(cell, True)
    objeto.add_attribute(cell, 'text', 1)  # Mostrar segunda columna

    conexion = conectar(datos_conexion)
    cursor = consultar(conexion, "*", tabla, " ORDER BY " + cod)
    datos = cursor.fetchall()
    cant = cursor.rowcount
    conexion.close()

    lista.clear()
    for i in range(0, cant):
        listafila = [datos[i][0], datos[i][1]]
        if tabla in ("ajustemotivos", "impuestos"):
            listafila.append(datos[i][2])
        elif tabla == "monedas_s":
            listafila.extend([datos[i][2], datos[i][3], datos[i][4]])
        elif tabla == "turnos":
            listafila.extend([str(datos[i][2]), str(datos[i][3])])
        lista.append(listafila)
Ejemplo n.º 2
0
def getHoursModel():
    global HOURS
    if HOURS is None:
        HOURS = ListStore(str)
        HOURS.set_sort_column_id(0, SortType.ASCENDING)
        for i in range(24):
            HOURS.append((str(i).zfill(2) + ':00', ))
    return HOURS
    def config_combo_total(self):
        lista = ListStore(int, str)
        self.obj("cmb_total").set_model(lista)

        cell = CellRendererText()
        self.obj("cmb_total").pack_start(cell, True)
        self.obj("cmb_total").add_attribute(cell, 'text', 1)

        lista.append([1, "Entre"])
        lista.append([2, "Mayor que..."])
        lista.append([3, "Mayor o igual que..."])
        lista.append([4, "Menor que..."])
        lista.append([5, "Menor o igual que..."])
Ejemplo n.º 4
0
def create_combo_box(model: Gtk.ListStore = None,
                     labels: List[str] = None) -> Gtk.ComboBox:
    if model is None:
        model = Gtk.ListStore(str)
    if labels is not None:
        for i in range(len(labels)):
            model.append([labels[i]])
    combo_box = Gtk.ComboBox.new_with_model(model)
    renderer_text = Gtk.CellRendererText()
    combo_box.pack_start(renderer_text, True)
    combo_box.add_attribute(renderer_text, "text", 0)
    combo_box.set_active(0)
    return combo_box
Ejemplo n.º 5
0
def copy_childrens(from_model: Gtk.TreeStore, to_model: Gtk.ListStore, iter_: Gtk.TreeIter, column: int) -> None:
    childrens = from_model.iter_n_children(iter_)

    if childrens:
        for index in range(childrens):
            children_iter = from_model.iter_nth_child(iter_, index)
            value = from_model.get_value(children_iter, column)

            if value:
                to_model.append([value])
            else:
                log.debug(
                    _("Ignoring value from %s on column %s item %s because value is empty"),
                    children_iter,
                    column,
                    index
                )
    else:
        value = from_model.get_value(iter_, column)
        to_model.append([value])
Ejemplo n.º 6
0
    def cmb_it_02_config(self):
        lista = ListStore(int, str, float)
        objeto.set_model(lista)

        cell = CellRendererText()
        objeto.pack_start(cell, True)
        objeto.add_attribute(cell, 'text', 2)

        conexion = Op.conectar(self.nav.datos_conexion)
        cursor = Op.consultar(conexion, "*", tabla, " ORDER BY " + cod)
        datos = cursor.fetchall()
        cant = cursor.rowcount
        conexion.close()

        lista.clear()
        for i in range(0, cant):
            listafila = [datos[i][0], datos[i][1]]
            if tabla in ("ajustemotivos", "impuestos"):
                listafila.append(datos[i][2])
            if tabla == "turnos":
                listafila.extend([str(datos[i][2]), str(datos[i][3])])
            lista.append(listafila)
Ejemplo n.º 7
0
    def configurar_combo_pagos(self):
        lista = ListStore(str)
        self.obj("cmb_pago").set_model(lista)

        cell = CellRendererText()
        self.obj("cmb_pago").pack_start(cell, True)
        self.obj("cmb_pago").add_attribute(cell, 'text', 0)

        lista.clear()
        lista.append(["Mensual"])
        lista.append(["Quincenal"])
        lista.append(["Semanal"])
Ejemplo n.º 8
0
def dummy_entries():
    store = ListStore(str)
    store.append(('First entry',))
    store.append(('Second entry',))
    store.append(('Third entry',))
    return store
Ejemplo n.º 9
0
class PeersTab(Tab):
    def __init__(self):
        super(PeersTab, self).__init__('Peers', 'peers_tab', 'peers_tab_label')

        self.peer_menu = self.main_builder.get_object('menu_peer_tab')
        component.get('MainWindow').connect_signals(self)

        self.listview = self.main_builder.get_object('peers_listview')
        self.listview.props.has_tooltip = True
        self.listview.connect('button-press-event',
                              self._on_button_press_event)
        self.listview.connect('query-tooltip', self._on_query_tooltip)

        # flag, ip, client, downspd, upspd, country code, int_ip, seed/peer icon, progress
        self.liststore = ListStore(Pixbuf, str, str, int, int, str, float,
                                   Pixbuf, float)
        self.cached_flag_pixbufs = {}

        self.seed_pixbuf = icon_seeding
        self.peer_pixbuf = icon_downloading

        # key is ip address, item is row iter
        self.peers = {}

        # Country column
        column = TreeViewColumn()
        render = CellRendererPixbuf()
        column.pack_start(render, False)
        column.add_attribute(render, 'pixbuf', 0)
        column.set_sort_column_id(5)
        column.set_clickable(True)
        column.set_resizable(True)
        column.set_expand(False)
        column.set_min_width(20)
        column.set_reorderable(True)
        self.listview.append_column(column)

        # Address column
        column = TreeViewColumn(_('Address'))
        render = CellRendererPixbuf()
        column.pack_start(render, False)
        column.add_attribute(render, 'pixbuf', 7)
        render = CellRendererText()
        column.pack_start(render, False)
        column.add_attribute(render, 'text', 1)
        column.set_sort_column_id(6)
        column.set_clickable(True)
        column.set_resizable(True)
        column.set_expand(False)
        column.set_min_width(100)
        column.set_reorderable(True)
        self.listview.append_column(column)

        # Client column
        column = TreeViewColumn(_('Client'))
        render = CellRendererText()
        column.pack_start(render, False)
        column.add_attribute(render, 'text', 2)
        column.set_sort_column_id(2)
        column.set_clickable(True)
        column.set_resizable(True)
        column.set_expand(False)
        column.set_min_width(100)
        column.set_reorderable(True)
        self.listview.append_column(column)

        # Progress column
        column = TreeViewColumn(_('Progress'))
        render = CellRendererProgress()
        column.pack_start(render, True)
        column.set_cell_data_func(render, cell_data_peer_progress, 8)
        column.set_sort_column_id(8)
        column.set_clickable(True)
        column.set_resizable(True)
        column.set_expand(False)
        column.set_min_width(100)
        column.set_reorderable(True)
        self.listview.append_column(column)

        # Down Speed column
        column = TreeViewColumn(_('Down Speed'))
        render = CellRendererText()
        column.pack_start(render, False)
        column.set_cell_data_func(render, cell_data_speed_down, 3)
        column.set_sort_column_id(3)
        column.set_clickable(True)
        column.set_resizable(True)
        column.set_expand(False)
        column.set_min_width(50)
        column.set_reorderable(True)
        self.listview.append_column(column)

        # Up Speed column
        column = TreeViewColumn(_('Up Speed'))
        render = CellRendererText()
        column.pack_start(render, False)
        column.set_cell_data_func(render, cell_data_speed_up, 4)
        column.set_sort_column_id(4)
        column.set_clickable(True)
        column.set_resizable(True)
        column.set_expand(False)
        column.set_min_width(50)
        # Bugfix: Last column needs max_width set to stop scrollbar appearing
        column.set_max_width(150)
        column.set_reorderable(True)
        self.listview.append_column(column)

        self.listview.set_model(self.liststore)

        self.load_state()

        self.torrent_id = None

    def save_state(self):
        # Get the current sort order of the view
        column_id, sort_order = self.liststore.get_sort_column_id()

        # Setup state dict
        state = {
            'columns': {},
            'sort_id': column_id,
            'sort_order': int(sort_order) if sort_order else None,
        }

        for index, column in enumerate(self.listview.get_columns()):
            state['columns'][column.get_title()] = {
                'position': index,
                'width': column.get_width(),
            }
        save_pickled_state_file('peers_tab.state', state)

    def load_state(self):
        state = load_pickled_state_file('peers_tab.state')

        if state is None:
            return

        if len(state['columns']) != len(self.listview.get_columns()):
            log.warning('peers_tab.state is not compatible! rejecting..')
            return

        if state['sort_id'] and state['sort_order'] is not None:
            self.liststore.set_sort_column_id(state['sort_id'],
                                              state['sort_order'])

        for (index, column) in enumerate(self.listview.get_columns()):
            cname = column.get_title()
            if cname in state['columns']:
                cstate = state['columns'][cname]
                column.set_sizing(TreeViewColumnSizing.FIXED)
                column.set_fixed_width(
                    cstate['width'] if cstate['width'] > 0 else 10)
                if state['sort_id'] == index and state[
                        'sort_order'] is not None:
                    column.set_sort_indicator(True)
                    column.set_sort_order(state['sort_order'])
                if cstate['position'] != index:
                    # Column is in wrong position
                    if cstate['position'] == 0:
                        self.listview.move_column_after(column, None)
                    elif (self.listview.get_columns()[cstate['position'] -
                                                      1].get_title() != cname):
                        self.listview.move_column_after(
                            column,
                            self.listview.get_columns()[cstate['position'] -
                                                        1])

    def update(self):
        # Get the first selected torrent
        torrent_id = component.get('TorrentView').get_selected_torrents()

        # Only use the first torrent in the list or return if None selected
        if len(torrent_id) != 0:
            torrent_id = torrent_id[0]
        else:
            # No torrent is selected in the torrentview
            self.liststore.clear()
            return

        if torrent_id != self.torrent_id:
            # We only want to do this if the torrent_id has changed
            self.liststore.clear()
            self.peers = {}
            self.torrent_id = torrent_id

        component.get('SessionProxy').get_torrent_status(
            torrent_id, ['peers']).addCallback(self._on_get_torrent_status)

    def get_flag_pixbuf(self, country):
        if not country.strip():
            return None

        if country not in self.cached_flag_pixbufs:
            # We haven't created a pixbuf for this country yet
            try:
                self.cached_flag_pixbufs[country] = Pixbuf.new_from_file(
                    deluge.common.resource_filename(
                        'deluge',
                        os.path.join('ui', 'data', 'pixmaps', 'flags',
                                     country.lower() + '.png'),
                    ))
            except Exception as ex:
                log.debug('Unable to load flag: %s', ex)
                return None

        return self.cached_flag_pixbufs[country]

    def _on_get_torrent_status(self, status):
        new_ips = set()
        for peer in status['peers']:
            new_ips.add(peer['ip'])
            if peer['ip'] in self.peers:
                # We already have this peer in our list, so lets just update it
                row = self.peers[peer['ip']]
                if not self.liststore.iter_is_valid(row):
                    # This iter is invalid, delete it and continue to next iteration
                    del self.peers[peer['ip']]
                    continue
                values = self.liststore.get(row, 3, 4, 5, 7, 8)
                if peer['down_speed'] != values[0]:
                    self.liststore.set_value(row, 3, peer['down_speed'])
                if peer['up_speed'] != values[1]:
                    self.liststore.set_value(row, 4, peer['up_speed'])
                if peer['country'] != values[2]:
                    self.liststore.set_value(row, 5, peer['country'])
                    self.liststore.set_value(
                        row, 0, self.get_flag_pixbuf(peer['country']))
                if peer['seed']:
                    icon = self.seed_pixbuf
                else:
                    icon = self.peer_pixbuf

                if icon != values[3]:
                    self.liststore.set_value(row, 7, icon)

                if peer['progress'] != values[4]:
                    self.liststore.set_value(row, 8, peer['progress'])
            else:
                # Peer is not in list so we need to add it

                # Create an int IP address for sorting purposes
                if peer['ip'].count(':') == 1:
                    # This is an IPv4 address
                    ip_int = sum(
                        int(byte) << shift for byte, shift in zip(
                            peer['ip'].split(':')[0].split('.'), (24, 16, 8,
                                                                  0)))
                    peer_ip = peer['ip']
                else:
                    # This is an IPv6 address
                    import socket
                    import binascii

                    # Split out the :port
                    ip = ':'.join(peer['ip'].split(':')[:-1])
                    ip_int = int(
                        binascii.hexlify(socket.inet_pton(socket.AF_INET6,
                                                          ip)), 16)
                    peer_ip = '[%s]:%s' % (ip, peer['ip'].split(':')[-1])

                if peer['seed']:
                    icon = self.seed_pixbuf
                else:
                    icon = self.peer_pixbuf

                row = self.liststore.append([
                    self.get_flag_pixbuf(peer['country']),
                    peer_ip,
                    peer['client'],
                    peer['down_speed'],
                    peer['up_speed'],
                    peer['country'],
                    float(ip_int),
                    icon,
                    peer['progress'],
                ])

                self.peers[peer['ip']] = row

        # Now we need to remove any ips that were not in status["peers"] list
        for ip in set(self.peers).difference(new_ips):
            self.liststore.remove(self.peers[ip])
            del self.peers[ip]

    def clear(self):
        self.liststore.clear()

    def _on_button_press_event(self, widget, event):
        """This is a callback for showing the right-click context menu."""
        log.debug('on_button_press_event')
        # We only care about right-clicks
        if self.torrent_id and event.button == 3:
            self.peer_menu.popup(None, None, None, None, event.button,
                                 event.time)
            return True

    def _on_query_tooltip(self, widget, x, y, keyboard_tip, tooltip):
        is_tooltip, x, y, model, path, _iter = widget.get_tooltip_context(
            x, y, keyboard_tip)
        if is_tooltip:
            country_code = model.get(_iter, 5)[0]
            if country_code != '  ' and country_code in COUNTRIES:
                tooltip.set_text(COUNTRIES[country_code])
                # widget here is self.listview
                widget.set_tooltip_cell(tooltip, path, widget.get_column(0),
                                        None)
                return True
        return False

    def on_menuitem_add_peer_activate(self, menuitem):
        """This is a callback for manually adding a peer"""
        log.debug('on_menuitem_add_peer')
        builder = Builder()
        builder.add_from_file(
            deluge.common.resource_filename(
                __package__, os.path.join('glade', 'connect_peer_dialog.ui')))
        peer_dialog = builder.get_object('connect_peer_dialog')
        txt_ip = builder.get_object('txt_ip')
        response = peer_dialog.run()

        if response:
            value = txt_ip.get_text()
            ip, port = parse_ip_port(value)
            if ip and port:
                log.info('Adding peer IP: %s port: %s to %s', ip, port,
                         self.torrent_id)
                client.core.connect_peer(self.torrent_id, ip, port)
            else:
                log.error('Error parsing peer "%s"', value)

        peer_dialog.destroy()
        return True
Ejemplo n.º 10
0
class Playlist:
    def __init__(self, extensionsloader):
        self.extensions = extensionsloader
        self.module = {'name': 'Playlist'}

        self.functions = Functions()
        self.userconf = ConfigLoader()

        self.config = {}
        rpt = self.userconf.config['Playlist']['repeat']
        self.config['repeat'] = bool(int(rpt))
        shf = self.userconf.config['Playlist']['shuffle']
        self.config['shuffle'] = bool(int(shf))
        shm = self.userconf.config['Playlist']['shuffle_mode']
        self.config['shuffle_mode'] = shm

        self.lastfm = LastFm()
        self.playlists_mgmnt = Playlists()

        self.playlist_content = {}
        self.playlist_identifier = 0
        self.playlist_current = None
        self.current_playlist_id = 0
        self.user_playlists = {}
        self.last_user_playlist = None

        self.similar_artists = []
        self.is_in_similar_thread = False

        # Create the Playlist view
        def launch_playlist(wdg):
            self.widgets = wdg[1]

            self.playlist_label = self.widgets.get_object('label_playlist')
            self.playlist_repeat = self.widgets.get_object('tool-repeat')
            self.playlist_shuffle = self.widgets.get_object('tool-shuffle')
            self.playlist_clean = self.widgets.get_object('tool-clean')
            self.playlist_combo = self.widgets.get_object('combo-playlist')
            self.playlist_save = self.widgets.get_object('tool-saveplaylist')
            self.playlist_lyrics = self.widgets.get_object('tool-lyrics')

            self.playlist_tree = self.widgets.get_object('treeview_playlist')
            self.playlist_tree.set_headers_visible(False)
            self.playlist_tree.props.reorderable = True
            self.playlist_tree.connect('key_press_event', self.key_pressed)
            self.playlist_tree.connect('row_activated', self.row_activated)

            self.liststore = ListStore(str, str, str, str, int)
            self.playlist_tree.set_model(self.liststore)

            renderer_pix = CellRendererPixbuf()
            column_pixbuf = TreeViewColumn('1', renderer_pix, icon_name=0)
            column_pixbuf.set_fixed_width(18)
            self.playlist_tree.append_column(column_pixbuf)

            renderer_text = CellRendererText()
            column_text = TreeViewColumn('2', renderer_text, markup=1)
            column_text.props.expand = True
            column_text.props.max_width = 192
            self.playlist_tree.append_column(column_text)

            column_text = TreeViewColumn('3', renderer_text, markup=2)
            column_text.set_fixed_width(40)
            self.playlist_tree.append_column(column_text)

            self.repeat_btn = self.widgets.get_object('tool-repeat')
            if self.config['repeat']:
                self.repeat_btn.set_active(True)
            self.repeat_btn.connect('clicked', self.toggle, 'repeat')

            self.shuffle_btn = self.widgets.get_object('tool-shuffle')
            if self.config['shuffle']:
                self.shuffle_btn.set_active(True)
            self.shuffle_btn.connect('clicked', self.toggle, 'shuffle')

            def clean_wdg(widget):
                # Clean playlist
                self.clean()

                # Show popover
                if self.current_playlist_id > 3:
                    self.clean_btn.set_sensitive(True)
                    self.clean_pop.show_all()

            self.clean_btn = self.widgets.get_object('tool-clean')
            self.clean_btn.connect('clicked', clean_wdg)
            self.clean_pop = Popover.new(self.clean_btn)
            self.clean_pop.set_size_request(100, 30)

            gtkpla = join(self.functions.datadir, 'glade', 'plist-del-pop.ui')
            win = gtk_builder()
            win.set_translation_domain('bluemindo')
            win.add_from_file(gtkpla)
            hbox = win.get_object('box-playlist')
            lbl = win.get_object('label')
            lbl.set_text(_('Do you also want to remove the playlist?'))
            btn = win.get_object('del-btn')
            btn.set_label(_('Delete'))
            btn.connect('clicked', self.delete_playlist)
            self.clean_pop.add(hbox)

            # Populate combobox
            self.combolist = ListStore(int, str)

            self.combobox = self.widgets.get_object('combobox')
            self.combobox.set_model(self.combolist)
            self.combobox.set_popup_fixed_width(False)
            self.combobox.props.expand = False

            renderer_text = CellRendererText()
            renderer_text.props.ellipsize = EllipsizeMode.END
            self.combobox.pack_start(renderer_text, True)
            self.combobox.set_entry_text_column(1)
            self.combobox.add_attribute(renderer_text, 'text', 1)

            self.combolist.append([0, _('Current')])
            self.combolist.append([1, _('Top 50 songs')])
            self.combolist.append([2, _('Top 10 albums')])

            playlists = self.playlists_mgmnt.get_playlists()

            if len(playlists) > 0:
                self.combolist.append([3, ''])
                item_id = 3

                playlists.sort(key=lambda it: it[1])
                for item in playlists:
                    item_id += 1
                    self.combolist.append([item_id, item])
                    self.user_playlists[item_id] = item
                    self.last_user_playlist = item_id

            def combo_sep(model, iter):
                if model[iter][0] == 3:
                    return True
            self.combobox.set_row_separator_func(combo_sep)

            def on_combo_changed(widget):
                path = widget.get_active()
                item_id = self.combolist[path][0]

                # First, clean the playlist
                self.clean(None)

                # Second, populate the playlist
                if item_id > 0:
                    self.populate(item_id)

                # Then, update playlist identifier
                self.current_playlist_id = item_id

                # Show delete/remove button if the playlist is from the user
                if item_id > 3:
                    self.clean_btn.set_sensitive(True)

            self.combobox.set_active(0)
            self.combobox.connect('changed', on_combo_changed)
            
            self.tool_save = self.widgets.get_object('tool-saveplaylist')
            self.tool_save.connect('clicked', self.save_playlist)
            self.save_pop = Popover.new(self.tool_save)
            self.save_pop.set_size_request(100, 30)

            gtkpla = join(self.functions.datadir, 'glade', 'plist-add-pop.ui')
            win = gtk_builder()
            win.set_translation_domain('bluemindo')
            win.add_from_file(gtkpla)
            hbox = win.get_object('box-playlist')
            self.save_pop.add(hbox)

            self.save_entry = win.get_object('save-entry')
            self.save_entry.connect('key_press_event', self.save_playlist_key)
            self.save_btn = win.get_object('save-btn')
            self.save_btn.connect('clicked', self.save_playlist_button)
            self.save_btn.set_label(_('Save'))

            self.clean_btn.set_sensitive(False)
            self.tool_save.set_sensitive(False)

        # Acquire the songs tree
        def acquire_tree(st):
            self.songs_tree = st

        self.extensions.connect('OnBluemindoStarted', launch_playlist)
        self.extensions.connect('OnSongsTreeCreated', acquire_tree)
        self.extensions.connect('OnSongQueued', self.on_new_song_queued)
        self.extensions.connect('OnAlbumQueued', self.on_new_album_queued)
        self.extensions.connect('AskPreviousSong', self.ask_previous_song)
        self.extensions.connect('AskNextSong', self.ask_next_song)
        self.extensions.connect('HasStartedSong', self.song_started)


    def toggle(self, widget, action):
        if action == 'repeat' and self.config['repeat']:
            self.config['repeat'] = False
            self.repeat_btn.set_active(False)
            self.userconf.update_key('Playlist', 'repeat', str(int(False)))
        elif action == 'repeat' and not self.config['repeat']:
            self.config['repeat'] = True
            self.repeat_btn.set_active(True)
            self.userconf.update_key('Playlist', 'repeat', str(int(True)))
        elif action == 'shuffle' and self.config['shuffle']:
            self.config['shuffle'] = False
            self.shuffle_btn.set_active(False)
            self.userconf.update_key('Playlist', 'shuffle', str(int(False)))
        elif action == 'shuffle' and not self.config['shuffle']:
            self.config['shuffle'] = True
            self.shuffle_btn.set_active(True)
            self.userconf.update_key('Playlist', 'shuffle', str(int(True)))

    def row_activated(self, widget, path, column):
        item_iter = self.liststore.get_iter(path)

        # Get the founded element.
        item_identifier = self.liststore.get_value(item_iter, 4)
        current_item = self.playlist_content[item_identifier]

        # The element is a song.
        if self.playlist_content[item_identifier].kind == 'song':
            self.playlist_current = [item_iter, item_identifier, None]
            self.extensions.load_event('OnPlayNewSong', current_item)
        # The element is an album.
        else:
            self.extensions.load_event('OnAbortPlayback')
            sng = self.playlist_content[item_identifier].tracks[0]
            self.playlist_current = [item_iter, item_identifier, 0]
            self.extensions.load_event('OnPlayNewSong', sng)

    def key_pressed(self, widget, eventkey):
        if eventkey.get_keyval()[1] == KEY_Delete:
            # Delete an item from the playlist
            selection = self.playlist_tree.get_selection()
            selected = selection.get_selected_rows()
            liststore = selected[0]
            listpath = selected[1]

            if len(listpath) > 0:
                selpath = listpath[0]
                playlist_identifier = liststore[selpath][4]

                # Are we removing the currently playing item?
                if self.playlist_current is not None:
                    item_iter, item_path, item_in_album = self.playlist_current
                    if selpath == TreePath.new_from_string(str(item_path)):
                        self.playlist_current = None

                # Removal
                del self.playlist_content[playlist_identifier]
                del liststore[selpath]

    def clean(self, data=None):
        self.playlist_content = {}
        self.playlist_identifier = 0
        self.playlist_current = None
        self.liststore.clear()

        # Update GUI
        self.clean_btn.set_sensitive(False)
        self.tool_save.set_sensitive(False)

    def populate(self, playlist_id):
        if playlist_id in (1, 2):
            # Automatic playlists based on listening stats
            if playlist_id == 1:
                tb = 'stats_songs'
                lm = 50
            elif playlist_id == 2:
                tb = 'stats_albums'
                lm = 10

            result = []
            txt = ('select * from %s order by tracks desc limit %u' % (tb, lm))

            sql = SQLite()
            cur = sql.execute(txt)
            for sg in cur:
                result.append(sg)
            sql.close()

            for item in result:
                if playlist_id == 1:
                    sng = Song(filename=item[0])
                    if hasattr(sng, 'title'):
                        self.on_new_song_queued(sng)
                elif playlist_id == 2:
                    album_name = item[0]
                    for it in self.songs_tree:
                        if album_name in self.songs_tree[it]:
                            self.on_new_album_queued(Album(it, album_name,
                                                           self.songs_tree))
                            break
        elif playlist_id > 3:
            # User-created playlists
            user_plist = self.user_playlists[playlist_id]
            plist = self.playlists_mgmnt.load_playlist(user_plist)

            for item in plist:
                sng = Song(filename=item)
                if hasattr(sng, 'title'):
                    self.on_new_song_queued(sng)

    def delete_playlist(self, widget):
        if self.current_playlist_id > 3:
            user_plist = self.user_playlists[self.current_playlist_id]
            self.playlists_mgmnt.delete_playlist(user_plist)

            # Delete the playlist from the list
            del self.user_playlists[self.current_playlist_id]

            cblid = 0
            for item in self.combolist:
                if item[0] == self.current_playlist_id:
                    del self.combolist[cblid]
                    break
                cblid += 1

            # Move back to "Current" playlist
            self.combobox.set_active(0)

    def save_playlist_key(self, widget, eventkey):
        if eventkey.get_keyval()[1] == KEY_Return:
            self.save_playlist_button(None)

    def save_playlist_button(self, widget):
        user_entry = self.save_entry.get_text()
        user_entry = user_entry.replace('\\', '-')
        user_entry = user_entry.replace('/', '-')
        user_entry = user_entry.replace('*', '-')
        user_entry = user_entry.replace('|', '-')

        if len(user_entry) > 0:
            rtn_value = self.playlists_mgmnt.create_new_playlist(user_entry)

            if rtn_value:
                self.save_pop.hide()

                # Add playlist to GUI
                if self.last_user_playlist is None:
                    self.combolist.append([3, ''])
                    self.last_user_playlist = 3

                self.last_user_playlist += 1
                self.combolist.append([self.last_user_playlist, user_entry])
                self.user_playlists[self.last_user_playlist] = user_entry

                # Write the playlist
                self.write_playlist(user_entry)

                # Select the new playlist
                self.combobox.set_active(self.last_user_playlist)

    def save_playlist(self, widget):
        if self.current_playlist_id < 3:
            # Create a new playlist
            self.save_entry.set_text('')
            self.save_pop.show_all()
        elif self.current_playlist_id > 3:
            # Update an existing playlist
            user_plist = self.user_playlists[self.current_playlist_id]
            self.write_playlist(user_plist)

    def write_playlist(self, user_plist):
        plist_content = []
        for item in self.liststore:
            item_id = item[4]
            plist_content.append(self.playlist_content[item_id])

        self.playlists_mgmnt.write_playlist(user_plist, plist_content)

    def on_new_song_queued(self, song_info):
        title = song_info.title
        artist = song_info.artist
        album = song_info.album
        filename = song_info.filename
        length = self.functions.human_length(song_info.length)

        self.liststore.append(('audio-x-generic-symbolic', '<b>' +
                               self.functions.view_encode(title, 99) +
                               '</b>\n' + self.functions.view_encode(artist),
                               '<span foreground="grey">' +
                               length + '</span>',
                               filename, self.playlist_identifier))

        self.playlist_content[self.playlist_identifier] = song_info
        self.playlist_identifier += 1

        # Update GUI
        self.clean_btn.set_sensitive(True)
        self.tool_save.set_sensitive(True)

    def on_new_album_queued(self, album_info):
        artist = album_info.artist
        album = album_info.name
        songs_count = str(len(album_info.tracks)) + ' ♫'

        self.liststore.append(('media-optical-symbolic', '<b>' +
                               self.functions.view_encode(album, 99) +
                               '</b>\n' + self.functions.view_encode(artist),
                               '<span foreground="grey">' +
                               songs_count + '</span>', '[album]',
                               self.playlist_identifier))

        self.playlist_content[self.playlist_identifier] = album_info
        self.playlist_identifier += 1

        # Update GUI
        self.clean_btn.set_sensitive(True)
        self.tool_save.set_sensitive(True)

    def ask_next_song(self, current_song):
        self.ask_for_a_song(True, current_song)

    def ask_previous_song(self, current_song):
        self.ask_for_a_song(False, current_song)

    def ask_for_a_song(self, next=True, current_song=None):
        def walk_in_playlist(item_iter, next=True):
            base_item_iter = item_iter
            if item_iter is None:
                # Find first song.
                item_iter = self.liststore.get_iter_first()
            elif next:
                # Find next song.
                path = self.liststore.get_path(self.playlist_current[0])
                path_int = int(path.to_string())
                max_id = len(self.playlist_content) - 1

                if (path_int + 1 <= max_id): # There is a song to launch!
                    item_iter = self.liststore.get_iter(path_int + 1)
                else: # There is no song to launch!
                    if not self.config['repeat']:
                        self.extensions.load_event('OnAbortPlayback')
                        return
                    else:
                        item_iter = self.liststore.get_iter_first()
            elif not next:
                # Find previous song.
                path = self.liststore.get_path(self.playlist_current[0])
                path_int = int(path.to_string())
                max_id = len(self.playlist_content) - 1

                if (path_int -1 >= 0): # There is a song to launch.
                    item_iter = self.liststore.get_iter(path_int - 1)
                else: # There is no song to launch!
                    if not self.config['repeat']:
                        self.extensions.load_event('OnAbortPlayback')
                        return
                    else:
                        item_iter = self.liststore.get_iter_from_string(str(max_id))

            # Get the founded element.
            item_identifier = self.liststore.get_value(item_iter, 4)
            current_item = self.playlist_content[item_identifier]

            def launch_founded_item(item_identifier, item_iter, current_item):
                # The element is a song.
                if self.playlist_content[item_identifier].kind == 'song':
                    self.playlist_current = [item_iter, item_identifier, None]
                    self.extensions.load_event('OnPlayNewSong', current_item)
                # The element is an album.
                else:
                    self.extensions.load_event('OnAbortPlayback')
                    sng = self.playlist_content[item_identifier].tracks[0]
                    sng.rg_mode_guess = 'album'
                    self.playlist_current = [item_iter, item_identifier, 0]
                    self.extensions.load_event('OnPlayNewSong', sng)

            # Are we currently listening from an album?
            if base_item_iter is not None:
                kind = self.playlist_content[self.playlist_current[1]].kind

                if kind == 'album':
                    base_item_identifier = self.liststore.get_value(base_item_iter, 4)
                    tracks = self.playlist_content[self.playlist_current[1]].tracks
                    max_sng = len(tracks) - 1

                    if next:
                        if self.playlist_current[2] < max_sng:
                            item_in_album = self.playlist_current[2] + 1
                        else:
                            return launch_founded_item(item_identifier, item_iter, current_item)
                    elif not next:
                        if self.playlist_current[2] - 1 > -1:
                            item_in_album = self.playlist_current[2] - 1
                        else:
                            return launch_founded_item(item_identifier, item_iter, current_item)

                    sng = self.playlist_content[base_item_identifier].tracks[item_in_album]
                    sng.rg_mode_guess = 'album'
                    self.playlist_current = [base_item_iter, base_item_identifier, item_in_album]
                    self.extensions.load_event('OnPlayNewSong', sng)
                    return

            launch_founded_item(item_identifier, item_iter, current_item)

        if len(self.playlist_content) == 0:
            # Playlist is empty.
            if not self.config['shuffle']:
                # Shuffle disabled: abort playback.
                self.extensions.load_event('OnAbortPlayback')
            else:
                # Shuffle enabled.
                if self.config['shuffle_mode'] == 'random':
                    # Random mode: seek for shuffle song.
                    self.extensions.load_event('AskShuffleSong')
                elif self.config['shuffle_mode'] == 'similar':
                    # Similar mode: seek for a similar song.
                    if len(self.similar_artists) == 0:
                        # No similar song founded: seek for any one.
                        self.extensions.load_event('AskShuffleSong')
                        return

                    # Choose one song in the list of similar artists
                    index = randrange(len(self.similar_artists))
                    artist = self.similar_artists[index]

                    mdb = MusicDatabase(None)
                    songs_list = mdb.load_from_artist(artist)
                    if len(songs_list) > 1:
                        index = randrange(len(songs_list))
                        song = songs_list[index]

                        sng = Song(filename=song[8])
                        print ('[SIMILAR] Playing a song from ' + sng.artist)
                        self.extensions.load_event('OnPlayNewSong', sng)
                    else:
                        self.extensions.load_event('AskShuffleSong')
        else:
            # Playlist is not empty, walk in it!
            if self.playlist_current is None:
                # Currently no current item in playlist, choose the first one!
                walk_in_playlist(None)
            else:
                # The current playling song is in the playlist!
                if next:
                    walk_in_playlist(self.playlist_current[0])
                else:
                    walk_in_playlist(self.playlist_current[0], False)


    def song_started(self, song):
        # First, try to download a few similar artists names
        if self.config['shuffle_mode'] == 'similar':
            def download_similars():
                threads_enter()
                art = self.lastfm.get_similar_artists(song.artist)

                self.similar_artists = []
                mdb = MusicDatabase(None)

                for artist in art:
                    if mdb.artist_exists(artist):
                        self.similar_artists.append(artist)

                self.is_in_similar_thread = False
                threads_leave()

            if not self.is_in_similar_thread:
                self.is_in_similar_thread = True
                thread = Thread(group=None, target=download_similars,
                                name='similars', args=())
                thread.start()

        # Second, update statistics for this song
        song.increment_statistics()
        alb = Album(song.artist, song.album, self.songs_tree)
        alb.increment_statistics()

        # Then, highlight currently playing song/album if it's in playlist
        if self.playlist_current is not None:
            # Currently playing item is in the playlist
            item_iter, item_path, item_in_album = self.playlist_current

            # Remove marker of all items
            for item in self.liststore:
                current_label = item[1]
                if current_label[:2] == '◎ ':
                    item[1] = current_label[2:]

            # Add marker on one item
            current_label = self.liststore[item_iter][1]
            if current_label[:2] != '◎ ':
                self.liststore[item_iter][1] = '◎ ' + current_label
Ejemplo n.º 11
0
class AlbumsView:
    def __init__(self, widgets, extensions):
        self.widgets = widgets
        self.extensions = extensions

        self.functions = Functions()
        self.userconf = ConfigLoader()
        self.dblclick = None

        # Create the IconView
        self.albumview = self.widgets[1].get_object('albumview')
        self.albummodel = ListStore(Pixbuf, str, str, str, int, str, str)

        self.albumview.set_pixbuf_column(0)
        self.albumview.set_markup_column(1)

        self.albumview.set_column_spacing(0)
        self.albumview.set_spacing(0)
        self.albumview.set_item_width(100)
        self.albumview.set_property('activate-on-single-click', False)

        # Add a filter to the ListStore model
        self.albumfilter = self.albummodel.filter_new(None)
        self.remove_filter_data()
        self.matched = False

        def filter_visible(model, iter, data):
            usrf = self.widgets[1].get_object('searchentry').get_text()
            search_a = model.get_value(iter, 3)
            search_b = model.get_value(iter, 2)
            pre_result = False

            if self.matched:
                usrf_a = self.matched[0]
                usrf_b = self.matched[1]

                if usrf_b == 'blm.!ARTIST!':
                    if usrf_a.lower() == search_b.lower():
                        # Matched an artist
                        pre_result = True
                else:   
                    if (usrf_a.lower() == search_a.lower() and
                        usrf_b.lower() == search_b.lower()):
                        # Matched an album
                        pre_result = True
            else:
                if len(model) > 0:
                    if (usrf.lower() in search_a.lower() or
                        usrf.lower() in search_b.lower()):
                        # Found an element (artist or album name is close)
                        pre_result = True
                    else:
                        # No element founded at all, return False anyway
                        return False

            # Apply filters
            fdg = self.filter_data['genre']
            fdy = self.filter_data['year']

            # Filter results by genres
            if fdg is not None and fdg != model.get_value(iter, 5):
                pre_result = False

            # Filter results by years
            if fdy is not None and fdy != model.get_value(iter, 6):
                pre_result = False

            # Return the final result
            return pre_result


        self.albumfilter.set_visible_func(filter_visible)
        self.albumview.set_model(self.albumfilter)

        # Connect to signals
        def grab_entry_focus(widget, event):
            key = event.string
            if (key.lower() in 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,'
                               'x,y,z,0,1,2,3,4,5,6,7,8,9'.split(',')):
                self.widgets[1].get_object('searchentry').grab_focus()
                self.widgets[1].get_object('searchentry').set_text(key)
                self.widgets[1].get_object('searchentry').set_position(-1)

        self.albumview.connect('key-press-event', grab_entry_focus)
        self.albumview.connect('selection_changed', self.on_selection_changed)


    def populate_albums(self, albums_tree, albums, songs_tree, search):
        self.albums_tree = albums_tree
        self.albums = albums
        self.songs_tree = songs_tree
        self.search_entry = search.searchentry

        # Clear the tree model first
        self.albummodel.clear()

        # Show albums in the main explorer view
        self.album_nf = []
        album_id = 0
        for alb in self.albums_tree:
            bdir = join(self.userconf.datadir, 'modules', 'player', 'covers')
            album = alb['album']
            artist = alb['artist']

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

            self.albums[album_id] = Album(artist, album, self.songs_tree)

            ap = self.albummodel.append([cover_px, '<b>' +
                                        self.functions.view_encode(album) +
                                        '</b>\n<span foreground="grey">' +
                                        self.functions.view_encode(artist) +
                                        '</span>',
                                        artist, album, album_id, '', ''])
            album_id += 1

            if not isfile(cover):
                self.album_nf.append([cover, ap, None])

        # Check if we have to regenerate thumbnail (cover not found at startup)
        if len(self.album_nf) > 0:
            def regenerate_thumb():
                new_album = []

                for alb in self.album_nf:
                    if isfile(alb[0]):
                        item_iter = alb[1]

                        cover_md5 = md5(open(alb[0], 'rb').read()).hexdigest()

                        if alb[2] == None or alb[2] != cover_md5:
                            cover_px = Pixbuf.new_from_file_at_scale(alb[0],
                                                                     150, 150,
                                                                     True)
                            self.albummodel.set_value(item_iter, 0, cover_px)
                            alb[2] = cover_md5
                            new_album.append(alb)
                    else:
                        new_album.append(alb)

                if len(new_album) > 0:
                    self.album_nf = new_album
                    return True

            timeout_add(15000, regenerate_thumb)


    def on_album_matched(self, album):
        for item in self.albummodel:
            if item[2] == album.artist and item[3] == album.name:
                self.on_selection_changed(self.albumview, album)


    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 play(self, usrobject):
        kind = usrobject.kind

        if kind == 'album':
            self.extensions.load_event('OnPlayNewAlbum', usrobject)
        else:
            self.extensions.load_event('OnPlayNewSong', usrobject)

    def queue(self, usrobject):
        kind = usrobject.kind

        if kind == 'album':
            self.extensions.load_event('OnAlbumQueued', usrobject)
        else:
            self.extensions.load_event('OnSongQueued', usrobject)

    def generate_filter_data(self, album_data):
        for element in self.albummodel:
            artist = element[2]
            album = element[3]

            datalb = album_data[artist][album]
            datalb_genre = datalb['genre']
            datalb_year = datalb['year']

            element[5] = datalb_genre
            element[6] = datalb_year

    def add_filter_data(self, value, field):
        self.filter_data[field] = value
        self.albumfilter.refilter()

    def remove_filter_data(self, cmb=None):
        if cmb is None:
            self.filter_data = {'genre': None, 'year': None}
        else:
            self.filter_data[cmb] = None
        self.albumfilter.refilter()
Ejemplo n.º 12
0
class QueuedTorrents(component.Component):
    def __init__(self):
        component.Component.__init__(
            self, 'QueuedTorrents', depend=['StatusBar', 'AddTorrentDialog']
        )
        self.queue = []
        self.status_item = None

        self.config = ConfigManager('gtk3ui.conf')
        self.builder = Builder()
        self.builder.add_from_file(
            deluge.common.resource_filename(
                __package__, os.path.join('glade', 'queuedtorrents.ui')
            )
        )
        self.builder.get_object('chk_autoadd').set_active(self.config['autoadd_queued'])
        self.dialog = self.builder.get_object('queued_torrents_dialog')
        self.dialog.set_icon(get_logo(32))

        self.builder.connect_signals(self)

        self.treeview = self.builder.get_object('treeview')
        self.treeview.append_column(
            TreeViewColumn(_('Torrent'), CellRendererText(), text=0)
        )

        self.liststore = ListStore(str, str)
        self.treeview.set_model(self.liststore)
        self.treeview.set_tooltip_column(1)

    def run(self):
        self.dialog.set_transient_for(component.get('MainWindow').window)
        self.dialog.show()

    def start(self):
        if len(self.queue) == 0:
            return

        # Make sure status bar info is showing
        self.update_status_bar()

        # We only want the add button sensitive if we're connected to a host
        self.builder.get_object('button_add').set_sensitive(True)

        if self.config['autoadd_queued'] or self.config['standalone']:
            self.on_button_add_clicked(None)
        else:
            self.run()

    def stop(self):
        # We only want the add button sensitive if we're connected to a host
        self.builder.get_object('button_add').set_sensitive(False)
        self.update_status_bar()

    def add_to_queue(self, torrents):
        """Adds the list of torrents to the queue"""
        # Add to the queue while removing duplicates
        self.queue = list(set(self.queue + torrents))

        # Update the liststore
        self.liststore.clear()
        for torrent in self.queue:
            if deluge.common.is_magnet(torrent):
                magnet = deluge.common.get_magnet_info(torrent)
                self.liststore.append([magnet['name'], torrent])
            else:
                self.liststore.append([os.path.split(torrent)[1], torrent])

        # Update the status bar
        self.update_status_bar()

    def update_status_bar(self):
        """Attempts to update status bar"""
        # If there are no queued torrents.. remove statusbar widgets and return
        if len(self.queue) == 0:
            if self.status_item is not None:
                component.get('StatusBar').remove_item(self.status_item)
                self.status_item = None
            return False

        try:
            component.get('StatusBar')
        except Exception:
            # The statusbar hasn't been loaded yet, so we'll add a timer to
            # update it later.
            timeout_add(100, self.update_status_bar)
            return False

        # Set the label text for statusbar
        if len(self.queue) > 1:
            label = str(len(self.queue)) + _(' Torrents Queued')
        else:
            label = str(len(self.queue)) + _(' Torrent Queued')

        # Add the statusbar items if needed, or just modify the label if they
        # have already been added.
        if self.status_item is None:
            self.status_item = component.get('StatusBar').add_item(
                icon='view-sort-descending',
                text=label,
                callback=self.on_statusbar_click,
            )
        else:
            self.status_item.set_text(label)

        # We return False so the timer stops
        return False

    def on_statusbar_click(self, widget, event):
        log.debug('on_statusbar_click')
        self.run()

    def on_button_remove_clicked(self, widget):
        selected = self.treeview.get_selection().get_selected()[1]
        if selected is not None:
            path = self.liststore.get_value(selected, 1)
            self.liststore.remove(selected)
            self.queue.remove(path)
            self.update_status_bar()

    def on_button_clear_clicked(self, widget):
        self.liststore.clear()
        del self.queue[:]
        self.update_status_bar()

    def on_button_close_clicked(self, widget):
        self.dialog.hide()

    def on_button_add_clicked(self, widget):
        # Add all the torrents in the liststore
        def add_torrent(model, path, _iter, data):
            torrent_path = deluge.common.decode_bytes(model.get_value(_iter, 1))
            process_args([torrent_path])

        self.liststore.foreach(add_torrent, None)
        del self.queue[:]
        self.dialog.hide()
        self.update_status_bar()

    def on_chk_autoadd_toggled(self, widget):
        self.config['autoadd_queued'] = widget.get_active()
Ejemplo n.º 13
0
class Filter:
    def __init__(self, widgets, aview):
        self.widgets = widgets

        self.functions = Functions()
        self.userconf = ConfigLoader()

        # GUI
        self.filter_button = self.widgets[1].get_object('tool-filter')
        self.filter_button.connect('clicked', self.on_button_clicked)

        gladefile = join(self.functions.datadir, 'glade', 'filterbar.ui')
        self.fbox = gtk_builder()
        self.fbox.set_translation_domain('bluemindo')
        self.fbox.add_from_file(gladefile)
        self.filter_box = self.fbox.get_object('infobar')

        wdg_place = self.widgets[1].get_object('filter-emplacement')
        wdg_place.add(self.filter_box)

        self.fbox.get_object('label_filter').set_text(_('Filter the results:'))

        # Create ComboBoxes
        self.genre_fstore = ListStore(int, str)
        self.genre_fcombo = self.fbox.get_object('combobox-genre')
        self.genre_fcombo.set_model(self.genre_fstore)
        renderer_text = CellRendererText()
        self.genre_fcombo.pack_start(renderer_text, True)
        self.genre_fcombo.set_entry_text_column(1)
        self.genre_fcombo.add_attribute(renderer_text, 'text', 1)

        self.year_fstore = ListStore(int, str)
        self.year_fcombo = self.fbox.get_object('combobox-year')
        self.year_fcombo.set_model(self.year_fstore)
        renderer_text = CellRendererText()
        self.year_fcombo.pack_start(renderer_text, True)
        self.year_fcombo.set_entry_text_column(1)
        self.year_fcombo.add_attribute(renderer_text, 'text', 1)

    def on_button_clicked(self, widget):
        if self.filter_box.props.visible is True:
            self.filter_box.hide()
        else:
            self.filter_box.show_all()

        # Reset filters
        self.genre_fcombo.set_active(0)
        self.year_fcombo.set_active(0)

    def launch(self, albums_tree, songs_tree, aview):
        self.albums_tree = albums_tree
        self.songs_tree = songs_tree
        self.aview = aview

        album_data = {}
        data_genre = []
        data_year = []

        # Gather data
        for item in self.albums_tree:
            item_artist = item['artist']
            item_album = item['album']

            if item_artist not in album_data.keys():
                album_data[item_artist] = {}

            album_data[item_artist][item_album] = {}

            album = Album(item_artist, item_album, self.songs_tree)

            album_genre = ''
            album_year = ''

            for sng in album.tracks:
                if album_genre == '':
                    album_genre = sng.genre

                if album_year == '':
                    album_year = sng.year

            if album_genre != '' and album_genre not in data_genre:
                data_genre.append(album_genre)

            if album_year != '' and album_year not in data_year:
                data_year.append(album_year)

            album_data[item_artist][item_album]['genre'] = album_genre
            album_data[item_artist][item_album]['year'] = album_year

        # Populate combobox
        self.genre_fstore.clear()
        self.genre_fstore.append([-2, _('All genres')])
        self.genre_fstore.append([-1, ''])

        data_genre.sort()
        i = 0
        for genre in data_genre:
            self.genre_fstore.append([i, genre])
            i += 1

        self.year_fstore.clear()
        self.year_fstore.append([-2, _('All years')])
        self.year_fstore.append([-1, ''])

        data_year.sort()
        i = 0
        for year in data_year:
            self.year_fstore.append([i, year])
            i += 1

        def combo_sep(model, iter):
            if model[iter][0] == -1:
                return True

        self.year_fcombo.set_row_separator_func(combo_sep)
        self.genre_fcombo.set_row_separator_func(combo_sep)

        self.aview.generate_filter_data(album_data)

        self.genre_fcombo.connect('changed', self.on_fcombo_changed, 'genre')
        self.year_fcombo.connect('changed', self.on_fcombo_changed, 'year')

        # Hide filters
        self.filter_box.hide()
        self.filter_button.set_active(False)

    def on_fcombo_changed(self, widget, cmb):
        path = widget.get_active()

        try:
            if cmb == 'genre':
                item_value = self.genre_fstore[path][1]
                item_key = self.genre_fstore[path][0]
            else:
                item_value = self.year_fstore[path][1]
                item_key = self.year_fstore[path][0]
        except IndexError:
            item_key = -42

        if item_key >= 0:
            self.aview.add_filter_data(item_value, cmb)
        else:
            self.aview.remove_filter_data(cmb)
Ejemplo n.º 14
0
class Search:
    def __init__(self, widgets, aview):
        self.widgets = widgets

        self.aview = aview
        self.albumview = aview.albumview
        self.albumfilter = aview.albumfilter
        self.matched = aview.matched

        self.functions = Functions()
        self.userconf = ConfigLoader()

        # Create the autocompletion columns
        self.completion_model = ListStore(Pixbuf, str, str, str, str, str, str,
                                          str)
        ecomplet = EntryCompletion()
        ecomplet.set_model(self.completion_model)

        pixbufcell = CellRendererPixbuf()
        ecomplet.pack_start(pixbufcell, False)
        ecomplet.add_attribute(pixbufcell, 'pixbuf', 0)

        markupcell = CellRendererText()
        markupcell.props.xpad = 10
        ecomplet.pack_start(markupcell, True)
        ecomplet.add_attribute(markupcell, 'markup', 1)

        markupcell = CellRendererText()
        markupcell.props.xpad = 5
        ecomplet.pack_start(markupcell, False)
        ecomplet.add_attribute(markupcell, 'markup', 2)

        pixbufcell = CellRendererPixbuf()
        ecomplet.pack_start(pixbufcell, False)
        ecomplet.add_attribute(pixbufcell, 'icon_name', 3)

        ecomplet.props.text_column = 4

        def matched(widget, model, iter):
            item = model[iter]
            data_a = item[4]
            data_b = item[5]

            self.aview.matched = [data_a, data_b]
            self.albumfilter.refilter()

            if data_b == 'blm.!ARTIST!':
                # Matched an artist: show albums
                return False
            elif exists(data_b):
                # Matched a song: queue to playlist
                sng = Song(filename=item[5])
                self.aview.queue(sng)

                # Go back to empty search
                self.aview.matched = False
                searchentry = widget.get_entry()
                searchentry.set_text('')
                return True
            #elif len(self.albumfilter) == 1:
            else:
                # Matched an album: load it in a panel
                album = Album(data_b, data_a, self.songs_tree)
                if hasattr(album, 'name'):
                    self.aview.on_album_matched(album)

                    # Go back to empty search
                    self.aview.matched = False
                    searchentry = widget.get_entry()
                    searchentry.set_text('')
                    return True

        ecomplet.connect('match-selected', matched)

        searchentry = self.widgets[1].get_object('searchentry')
        searchentry.set_completion(ecomplet)
        searchentry.grab_focus()

        def do_filter(widget):
            self.albumfilter.refilter()
            self.aview.matched = False

        searchentry.connect('changed', do_filter)
        self.searchentry = searchentry

    def generate_autocompletion(self, artists, albums, songs_tree):
        self.songs_tree = songs_tree

        albums_without_cover = []
        artists_without_picture = []

        # Launch autocompletion now that the songs tree is generated
        def append_autocompletion(name, kind):
            fnf = join(self.functions.datadir, 'image', 'logo_head_big.png')

            if kind == 1:
                # Artist
                icon = 'face-smile-symbolic'

                pic = join(self.userconf.datadir, 'modules', 'explorer',
                           'artists', self.functions.get_hash(name, 'picture'))

                try:
                    if isfile(pic):
                        pxbf = Pixbuf.new_from_file_at_scale(pic, 70, 70, True)
                    else:
                        pxbf = Pixbuf.new_from_file_at_scale(fnf, 70, 70, True)
                        artists_without_picture.append(name)
                except GLIBError:
                    pxbf = Pixbuf.new_from_file_at_scale(fnf, 70, 70, True)

                dname = '<b>' + self.functions.view_encode(name, 99) + '</b>'

                infos = ('<b>' + _('Artist') + '</b>\n' +
                         _('%s albums in collection.' %
                           ('<b>' + str(len(self.songs_tree[name])) + '</b>')))

                add = 'blm.!ARTIST!'
                add_a = ''
                add_b = ''
            elif kind == 2:
                # Album
                icon = 'media-optical-symbolic'

                artist = name[0]
                name = name[1]

                cover = join(self.userconf.datadir, 'modules', 'player',
                             'covers', self.functions.get_hash(name, artist))
                if isfile(cover):
                    pxbf = Pixbuf.new_from_file_at_scale(cover, 70, 70, True)
                else:
                    pxbf = Pixbuf.new_from_file_at_scale(fnf, 70, 70, True)
                    albums_without_cover.append([artist, name])

                dname = ('<b>' + self.functions.view_encode(name, 99) +
                         '</b>\n<i>' + self.functions.view_encode(artist, 99) +
                         '</i>')

                length = 0
                songs = 0
                for song in self.songs_tree[artist][name]:
                    songs += 1
                    length += song[7]

                hlgth = self.functions.human_length(length)
                infos = (_('%s songs' % ('<b>' + str(songs) + '</b>')) + '\n' +
                         _('Total playing time: %s.' %
                           ('<i>' + hlgth + '</i>')))

                self.cur_pxbf = pxbf

                add = artist
                add_a = ''
                add_b = ''
            elif kind == 3:
                # Song
                icon = 'media-record-symbolic'

                artist = name[1]
                album = name[2]

                add = name[8]
                add_a = artist
                add_b = album

                name = name[0]

                dname = ('<b>' + self.functions.view_encode(name, 99) +
                         '</b>\n<i>' + self.functions.view_encode(artist, 99) +
                         ' - ' + self.functions.view_encode(album, 99) +
                         '</i>')

                infos = '<b>' + _('Song') + '</b>'

                pxbf = self.cur_pxbf

            self.completion_model.append(
                [pxbf, dname, infos, icon, name, add, add_a, add_b])

        self.completion_model.clear()

        for a in artists:
            append_autocompletion(a, 1)

        for a in albums:
            append_autocompletion(a, 2)

            for sng in self.songs_tree[a[0]][a[1]]:
                append_autocompletion(sng, 3)

        # Retrieve album covers
        lastfm = LastFm()
        thread = Thread(group=None,
                        target=lastfm.get_albums_pictures,
                        name='coverart',
                        kwargs={'albums': albums_without_cover})
        thread.start()

        # Retrieve artist pictures
        thread = Thread(group=None,
                        target=lastfm.get_artists_pictures,
                        name='coverart',
                        kwargs={'artists': artists_without_picture})
        thread.start()
Ejemplo n.º 15
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)
Ejemplo n.º 16
0
class Model:
    """ Holds the application's data, as well as operations on them.

    The Model consists of four sub-models that correspond to the four main window parts:
    Flow Schedule, Zones, Zone Inspector and Playlists.
    """
    def __init__(self):
        """ Initialize sub-models.

        Do not initialize the zoneInspector sub-model,
        because no zone exists on application startup.
        """
        # Weekly Schedule Model
        self.schedule = {}
        for dayIndex in range(7):
            self.schedule[dayIndex] = ListStore(str, str)
            self.schedule[dayIndex].set_sort_column_id(0, SortType.ASCENDING)

        # Zone Model
        self.zones = ListStore(str, str, str, str)
        self.zones.set_sort_column_id(0, SortType.ASCENDING)

        # Zone Inspector Model
        self.zoneInspector = {}

        # Playlist Model
        self.playlists = ListStore(str, str)
        self.playlists.set_sort_column_id(0, SortType.ASCENDING)

    # Public methods

    def addZoneToDatabase(self,
                          zoneName,
                          zoneMaintainers='',
                          zoneDescription='',
                          zoneComments=''):
        """ Add a zone to the database.

        Subsequently, initialize its inspector.
        """
        self.zones.append(
            (zoneName, zoneDescription, zoneMaintainers, zoneComments))
        self.initZoneInspector(zoneName)

    def removeZoneFromDatabase(self, zoneRow):
        """
        Remove a zone from the database.

        Subsequently, remove every occurrence of it in the Flow Schedule.
        Also remove its inspector.
        """
        zoneName = self.zones[zoneRow][0]
        del self.zones[zoneRow]
        for dayIndex in range(7):
            while True:
                scheduleRow = self.getRowOfItemInColumnOfModel(
                    zoneName, 1, self.schedule[dayIndex])
                if scheduleRow is not None:
                    del self.schedule[dayIndex][scheduleRow]
                else:
                    break
        self.zoneInspector[zoneName].clear()
        del self.zoneInspector[zoneName]

    def editZoneNameInDatabase(self, oldZoneName, newZoneName):
        """ Edit a zone's name in the database.

        Subsequently, rename every occurrence of it in the Flow Schedule.
        Also rename its inspector.
        """
        zoneRow = self.getZoneRow(oldZoneName)
        self.zones[zoneRow][0] = newZoneName
        for dayIndex in range(7):
            while True:
                scheduleRow = self.getRowOfItemInColumnOfModel(
                    oldZoneName, 1, self.schedule[dayIndex])
                if scheduleRow is not None:
                    self.schedule[dayIndex][scheduleRow][1] = newZoneName
                else:
                    break
        self.initZoneInspector(newZoneName)
        self.zoneInspector[newZoneName] = self.zoneInspector[oldZoneName]
        del self.zoneInspector[oldZoneName]

    def addPlaylistToDatabase(self, playlistPath):
        """ Add a playlist to the database. """
        playlistName = getPlaylistNameFromPath(playlistPath)
        self.playlists.append((playlistName, playlistPath))

    def removePlaylistFromDatabase(self, playlistRow):
        """ Remove a playlist from the database.

        Subsequently, remove it from every zone in the database.
        """
        playlistName = self.playlists[playlistRow][0]
        del self.playlists[playlistRow]
        for zone in self.zones:
            zoneName = zone[0]
            while True:
                zoneInspectorRow = self.getRowOfItemInColumnOfModel(
                    playlistName, 0, self.zoneInspector[zoneName])
                if zoneInspectorRow is not None:
                    del self.zoneInspector[zoneName][zoneInspectorRow]
                else:
                    break

    def addZoneToSchedule(self, dayIndex, zoneName, zoneStartTime='00:00'):
        """ Add zoneName to the day that corresponds to dayIndex in Flow Schedule. """
        self.schedule[dayIndex].append((zoneStartTime, zoneName))

    def removeZoneFromSchedule(self, dayIndex, scheduleRow):
        """ Remove a zone from the day that corresponds to dayIndex in Flow Schedule. """
        del self.schedule[dayIndex][scheduleRow]

    def addPlaylistToZone(self, zoneName, playlist):
        """ Add playlist to zoneName. """
        self.zoneInspector[zoneName].append(
            (playlist.name, playlist.type, playlist.shuffle,
             playlist.schedIntervalMins, playlist.numSchedItems,
             playlist.fadeInSecs, playlist.fadeOutSecs, playlist.minLevel,
             playlist.maxLevel))

    def removePlaylistFromZone(self, zoneName, zoneInspectorRow):
        """ Remove the playlist located in zoneInspectorRow from zoneName. """
        del self.zoneInspector[zoneName][zoneInspectorRow]

    def zoneExistsInDatabase(self, zoneName):
        """ Return true if zoneName exists in database. """
        return self.itemExistsInColumnOfModel(zoneName, 0, self.zones)

    def playlistExistsInDatabase(self, playlistName):
        """ Return true if playlistName exists in database. """
        return self.itemExistsInColumnOfModel(playlistName, 0, self.playlists)

    def zoneHasMainPlaylist(self, zoneName):
        """ Return true if zoneName has a Main playlist. """
        return self.itemExistsInColumnOfModel('Main', 1,
                                              self.zoneInspector[zoneName])

    def getZoneRow(self, zoneName):
        """ Return the zoneName's row in Zones. """
        return self.getRowOfItemInColumnOfModel(zoneName, 0, self.zones)

    def getPlaylistRow(self, playlistName):
        """ Return the playlistName's row in Playlists. """
        return self.getRowOfItemInColumnOfModel(playlistName, 0,
                                                self.playlists)

    def getMainPlaylistRow(self, zoneName):
        """ Return the Main playlist's row of zoneName in zoneInspector. """
        return self.getRowOfItemInColumnOfModel('Main', 1,
                                                self.zoneInspector[zoneName])

    def getFallbackPlaylistRow(self, zoneName):
        """ Return the Fallback playlist's row of zoneName in zoneInspector. """
        return self.getRowOfItemInColumnOfModel('Fallback', 1,
                                                self.zoneInspector[zoneName])

    def attemptToAddDefaultPlaylistsToZone(self, zoneName):
        """ Add default playlists to zoneName, if they exist in database. """
        if self.playlistExistsInDatabase('fallback'):
            playlist = Playlist('fallback', 'Fallback', True, '', '', '2', '2',
                                '0', '1')
            self.addPlaylistToZone(zoneName, playlist)
        if self.playlistExistsInDatabase('Spots'):
            playlist = Playlist('Spots', 'Intermediate', True, '70', '1', '',
                                '', '', '')
            self.addPlaylistToZone(zoneName, playlist)
        if self.playlistExistsInDatabase('Jingles'):
            playlist = Playlist('Jingles', 'Intermediate', True, '40', '1', '',
                                '', '', '')
            self.addPlaylistToZone(zoneName, playlist)

    # Private methods

    def itemExistsInColumnOfModel(self, item, column, model):
        """ If item exists in model's column, return true. """
        return any((row[column] == item for row in model))

    def getRowOfItemInColumnOfModel(self, item, column, model):
        """ If item exists in model's column, return its row. """
        for i in range(len(model)):
            treeiter = model.get_iter(TreePath(i))
            if model[treeiter][column] == item:
                return treeiter
        return None

    def initZoneInspector(self, zoneName):
        """ Initialize zoneName's inspector. """
        self.zoneInspector[zoneName] = ListStore(str, str, bool, str, str, str,
                                                 str, str, str)
        self.zoneInspector[zoneName].set_sort_column_id(1, SortType.DESCENDING)