예제 #1
0
def paivita_paikalliset_tietokannat(logitiedosto=None):
    '''
	Katso, onko paikallinen tietokantatiedosto ajan tasalla.
	'''
    # Tietokantatyyppi kerrallaan
    for kansiotyyppi in kvak.LOKAALIT_TIETOKANNAT:
        logfun.kirjaa(logitiedosto,
                      f"Päivitetään paikallinen tietokanta {kansiotyyppi}.")
        tiedostotyyppi = Tiedosto
        if kansiotyyppi == "Musiikki":
            tiedostotyyppi = Biisi
        # Tietokantatiedosto kerrallaan
        for tietokantatiedosto in kvak.LOKAALIT_TIETOKANNAT[kansiotyyppi]:
            # Varmuuskopioi
            shutil.copy(tietokantatiedosto, "{}.bk".format(tietokantatiedosto))
            logfun.kirjaa(logitiedosto,
                          f"{kansiotyyppi}:{tietokantatiedosto} aloita")
            puu = Tiedostopuu(tiedostotyyppi=tiedostotyyppi)
            f = open(tietokantatiedosto, "r")
            puu.lue_tiedostosta(f)
            f.close()
            # muunna_paivaysformaatti(puu) # aja vain kerran
            puu = paivita_puu(puu, logitiedosto)
            f = open(tietokantatiedosto, "w+")
            f.write(str(puu))
            f.close()
            os.remove("{}.bk".format(tietokantatiedosto))
            logfun.kirjaa(logitiedosto,
                          f"{kansiotyyppi}:{tietokantatiedosto} valmis")
예제 #2
0
def kasaa_tietokanta(kansiotyyppi):
    '''
	Alusta annetun tyyppinen tietokanta.
	'''
    tiedostotyyppi = Tiedosto
    if kansiotyyppi == "Musiikki":
        tiedostotyyppi = Biisi
    for k, tietokansio in enumerate(
            kvak.KANSIOT[kvak.LOKAALI_KONE][kansiotyyppi]):
        puu = Tiedostopuu(tietokansio, None, 0, tiedostotyyppi, False)
        puu.kansoita()
        kohdetiedosto = kvak.LOKAALIT_TIETOKANNAT[kansiotyyppi][k]
        f = open(kohdetiedosto, "w+")
        f.write(str(puu))
        f.close()
예제 #3
0
    def kansoita_artistirakenne(self, puu):
        '''
        Täytä puun tiedot artisti/albumi/biisi -jaottelulla.
        Juuren alla kasa artisteja (Artistielementti)
        joiden alla kasa albumeita (Albumielementti)
        joiden alla kasa biisejä (Raitaelementti).

        Sisään
        ------
        puu : Tiedostopuu, Artistipuu tai dict
            Puu jonka tiedot rykäistään hierarkiseksi puuksi.
            Jos Tiedostopuu tai dict, sen pohjalta tuotetaan Artistipuu.
            Siinä menee yleensä hetki.
        '''
        if isinstance(puu, Artistipuu):
            artistipuu = puu
        elif isinstance(puu, dict):
            tiedostopuu = Tiedostopuu.diktista(puu)
            artistipuu = Artistipuu(tiedostopuu)
        elif isinstance(puu, Tiedostopuu):
            artistipuu = Artistipuu(puu)
        else:
            errmsg = (
                "Odotettiin artistipuuksi Tiedostopuu, Artistipuu tai dict" +
                f", saatiin {type(puu)}")
            LOGGER.error(errmsg)
            raise ValueError(errmsg)
        # Tyhjää edelliset
        self.puumalli.clear()
        self.juurisolmu = self.puumalli.invisibleRootItem()
        # Täytä uudet
        for artisti in artistipuu.artistit:
            artistielementti = Artistielementti(artistipuu, artisti)
            self.juurisolmu.appendRow(artistielementti)
        self.kansoitettu = True
 def populoi_hakutuloksilla(self):
     hakutulokset = self.hakukentta.hae()
     if not hakutulokset:
         LOGGER.debug("Hakutermit ei kunnolliset.")
         oli_tuloksia = False
         tulokset = {}
     else:
         haku = Hakukriteerit(hakutulokset)
         oli_tuloksia, tulokset = haku.etsi_tietokannasta(self.tietokanta)
     if oli_tuloksia:
         # Näytä tiedostopuuna
         if (self.nakyvat.get("selauspuu_tiedosto")
                 or self.nakyvat.get("selauspuu_hakutulos_tiedosto")):
             self.nakyvat = {
                 avain: (False if avain != "selauspuu_hakutulos_tiedosto"
                         else True)
                 for avain in self.nakyvat
             }
         # Näytä artistipuuna
         else:
             self.nakyvat = {
                 avain:
                 (False if avain != "selauspuu_hakutulos_artisti" else True)
                 for avain in self.nakyvat
             }
         self.hakutulos_tiedostopuu = tulokset
         self.hakutulos_artistipuu = Artistipuu(tulokset)
         self.selauspuu_hakutulos_tiedosto.kansoita_tiedostorakenne(
             self.hakutulos_tiedostopuu)
         self.selauspuu_hakutulos_artisti.kansoita_artistirakenne(
             self.hakutulos_artistipuu)
         self.aseta_puunakyma()
         self.aktiivipuu.expandAll()
     # Jos ei tuloksia, näytä alkuperäinen puu
     else:
         # Näytä tiedostopuuna
         if (self.nakyvat.get("selauspuu_tiedosto")
                 or self.nakyvat.get("selauspuu_hakutulos_tiedosto")):
             self.nakyvat = {
                 avain: (False if avain != "selauspuu_tiedosto" else True)
                 for avain in self.nakyvat
             }
         # Näytä artistipuuna
         else:
             self.nakyvat = {
                 avain: (False if avain != "selauspuu_artisti" else True)
                 for avain in self.nakyvat
             }
         self.hakutulos_tiedostopuu = Tiedostopuu()
         self.hakutulos_artistipuu = Artistipuu()
         self.aseta_puunakyma()
예제 #5
0
 def lue_tietokanta(self):
     '''Lue tietokanta.
     Jos tietokantaa ei löydy tiedostona määritellystä sijainnista,
     hae se palvelimelta.
     '''
     tiedostosijainti = os.path.join(self.asetukset.tietokantojen_sijainti,
                                     f"{self.nimi}.json")
     LOGGER.debug(f"Onko tiedosto {tiedostosijainti} olemassa:" +
                  f" {os.path.exists(tiedostosijainti)}")
     if os.path.exists(tiedostosijainti):
         LOGGER.debug(f"Luetaan tietokanta {self.nimi}" +
                      f" sijainnista {tiedostosijainti}.")
         with open(tiedostosijainti, "r", encoding="utf-8") as filu:
             dikti = json.load(filu)
             tiedostopuu = Tiedostopuu.diktista(dikti)
             LOGGER.debug("Luettiin.")
             self.signaali_vastaus.emit(tiedostopuu)
             LOGGER.debug(f"Valmis.")
             self.signaali_valmis.emit()
     else:
         LOGGER.debug(f"Ladataan tietokanta {self.nimi}" +
                      f" palvelimelta {self.osoite}.")
         self.luo_tarvittavat_kansiot()
         vastaus = musapet.lataa_tietokanta(self.nimi, self.osoite)
         if vastaus.virhe:
             LOGGER.debug(f"Virhe: {vastaus.virhe}")
             self.signaali_virhe.emit(vastaus.virhe)
         else:
             LOGGER.debug(f"Vastaus: {type(vastaus.vastaus)}")
             tietokanta = Tiedostopuu.diktista(vastaus.vastaus)
             LOGGER.debug(
                 f"Kirjoitetaan ladattu tietokanta tiedostoon {tiedostosijainti}"
             )
             with open(tiedostosijainti, "w+", encoding="utf-8") as filu:
                 json.dump(vastaus.vastaus, filu)
                 self.signaali_vastaus.emit(tietokanta)
         LOGGER.debug(f"Valmis.")
         self.signaali_valmis.emit()
예제 #6
0
    def kansoita_tiedostorakenne(self, puu):
        '''
        Täytä puun tiedot kansio/alikansio/biisi -rakenteella.
        Juuren alla kasa kansioita (Kansioelementti),
        joiden alla kasa tiedostoja (Tiedostoelementti)

        Sisään
        ------
        puu : Tiedostopuu tai dict
            Puu jonka tiedoilla hierarkia täytetään.
            Saa olla joko valmiina Tiedostopuuna tai dictinä
            jonka voi sellaiseksi lukea.
        '''
        # Tyhjää edelliset
        self.puumalli.clear()
        self.juurisolmu = self.puumalli.invisibleRootItem()

        # Täytä uudet
        def kansoita_puulla(puu, juuri, edellinen):
            fkoko = 10
            # Ylempänä juuressa isompi fonttikoko ("pääkansiot")
            if juuri < 2:
                fkoko = 12

            # Elementin väri vuorotteleva & hiipuva
            r = min(255, max(255 + (-1 + 2 * (juuri % 2)) * juuri * 25, 0))
            g = min(255, max(255 + (1 - 2 * (juuri % 2)) * juuri * 25, 0))
            b = min(255, max(255 - juuri * 25, 0))
            elementti = Kansioelementti(puu, fonttikoko=fkoko, vari=(r, g, b))
            # Täytä kansion alle kaikki mitä sen alle kuuluu
            for alikansio in puu.alikansiot:
                kansoita_puulla(alikansio, juuri + 1, elementti)
            for biisi in puu.tiedostot:
                biisielementti = Tiedostoelementti(biisi)
                elementti.appendRow(biisielementti)
            edellinen.appendRow(elementti)

        if isinstance(puu, dict):
            tiedostopuu = Tiedostopuu.diktista(puu)
        elif isinstance(puu, Tiedostopuu):
            tiedostopuu = puu
        else:
            errmsg = ("Odotettiin tiedostopuuksi Tiedostopuu tai dict" +
                      f", saatiin {type(puu)}")
            LOGGER.error(errmsg)
            raise ValueError(errmsg)
        kansoita_puulla(puu, juuri=0, edellinen=self.juurisolmu)
        self.kansoitettu = True
예제 #7
0
    def lataa(self):
        '''Lataa tietokanta nimen perusteella.

        Emittoi
        -------
        signaali_virhe : str
            Jos jokin meni pieleen, virhekuvaus.
        signaali_vastaus : Tiedostopuu
            Ladattu puu.
        signaali_valmis
            Kun toimenpide valmis (oli tulos mikä hyvänsä)
        '''
        LOGGER.debug(f"Lataa tietokanta {self.nimi} osoitteesta {self.osoite}")
        vastaus = musapet.lataa_tietokanta(self.nimi, self.osoite)
        if vastaus.virhe:
            LOGGER.debug(f"Virhe: {vastaus.virhe}")
            self.signaali_virhe.emit(vastaus.virhe)
        else:
            LOGGER.debug(f"Vastaus: {type(vastaus.vastaus)}")
            tietokanta = Tiedostopuu.diktista(vastaus.vastaus)
            self.signaali_vastaus.emit(tietokanta)
        LOGGER.debug(f"Valmis.")
        self.signaali_valmis.emit()
예제 #8
0
def synkkaa(logitiedosto=None):
    '''
	Synkkaa paikalliset tiedostot ulkoisten tiedostojen kanssa.
	Se, mikä liikkuu mihinkin suuntaan on määritelty kansiovakioiden puolella.
	'''
    # Jos Pettankone, päivitetään vain paikalliset tietokannat
    if kvak.LOKAALI_KONE == "Pettan":
        print("Pettankone, päivitetään vain paikalliset tietokannat.")
        logfun.kirjaa(logitiedosto,
                      "Pettankone, päivitetään vain paikalliset tietokannat.")
        paivita_paikalliset_tietokannat(logitiedosto=logitiedosto)
        return (1)
    # Ei tehdä mitään jos asioita ei ole määritelty
    if None in [kvak.VOIMASUHTEET, kvak.LOKAALIT_TIETOKANNAT]:
        print("Tietokonetta ei määritelty kansiovakioissa, ei tehdä mitään.")
        logfun.kirjaa(
            logitiedosto,
            "Tietokonetta ei määritelty kansiovakioissa, ei tehdä mitään.")
        return (0)

    # Varmistetaan että tietokannat on olemassa
    logfun.kirjaa(logitiedosto,
                  "Tarkistetaan paikallisten tietokantojen olemassaolo.")
    tarkista_onko_tietokannat(logitiedosto=logitiedosto)
    # Varmistetaan että ovat ajan tasalla
    logfun.kirjaa(logitiedosto,
                  "Tarkistetaan paikallisten tietokantojen ajantasaisuus.")
    paivita_paikalliset_tietokannat(logitiedosto=logitiedosto)

    # Kullekin tiedostokansiolle: kopioi Pettanin tietokantatiedosto ja vertaa sitä omaan
    for kansiotyyppi in kvak.LOKAALIT_TIETOKANNAT:
        pettanin_tietokanta = kvak.TIETOKANNAT["Pettan"][
            kansiotyyppi]  # lista tiedostopolkuja, valkkaa oikea
        lokaali_tietokanta = kvak.LOKAALIT_TIETOKANNAT[kansiotyyppi][0]
        # Yritä siirtää max. viisi kertaa
        siirretty = False
        for yritys in range(5):
            siirretty = kfun.lataa(
                True, "pettankone",
                pettanin_tietokanta[kvak.VOIMASUHTEET[kansiotyyppi][1]], None,
                f"pettan_{kansiotyyppi}.tietokanta")
            if siirretty:
                break
        if siirretty:
            # Lue tietokantatiedostoista
            logfun.kirjaa(
                logitiedosto,
                f"Tietokanta \"{kansiotyyppi}\" kopioitu pettanilta")
            if kansiotyyppi == "Musiikki":
                puu_lokaali = Tiedostopuu(tiedostotyyppi=Biisi)
                puu_pettan = Tiedostopuu(tiedostotyyppi=Biisi)
            else:
                puu_lokaali = Tiedostopuu(tiedostotyyppi=Tiedosto)
                puu_pettan = Tiedostopuu(tiedostotyyppi=Tiedosto)
            f = open(lokaali_tietokanta, "r")
            puu_lokaali.lue_tiedostosta(f)
            logfun.kirjaa(logitiedosto,
                          f"Paikallinen puu {lokaali_tietokanta} luettu.")
            f.close()
            f = open(f"pettan_{kansiotyyppi}.tietokanta", "r")
            puu_pettan.lue_tiedostosta(f)
            logfun.kirjaa(logitiedosto, f"Pettanin puu {kansiotyyppi} luettu.")
            f.close()

            # Vertaa tietokantatiedostoja
            # Paikallinen kone masteri
            if kvak.VOIMASUHTEET[kansiotyyppi][0]:
                logfun.kirjaa(logitiedosto,
                              "Verrataan puita, paikallinen puu masteri.")
                puu_pettan = vertaa_puita(isantapuu=puu_lokaali,
                                          isantapalvelin=None,
                                          lapsipuu=puu_pettan,
                                          lapsipalvelin="pettankone",
                                          logitiedosto=logitiedosto)
                f = open(f"pettan_{kansiotyyppi}.tietokanta", "w+")
                f.write(str(puu_pettan))
                f.close()

            # Pettani masteri
            else:
                logfun.kirjaa(logitiedosto,
                              "Verrataan puita, Pettani masteri.")
                puu_lokaali = vertaa_puita(isantapuu=puu_pettan,
                                           isantapalvelin="pettankone",
                                           lapsipuu=puu_lokaali,
                                           lapsipalvelin=None,
                                           logitiedosto=logitiedosto)
                f = open(lokaali_tietokanta, "w+")
                f.write(str(puu_lokaali))
                f.close()

            # Päivitä Pettanilla sijaitseva tietokantatiedosto
            logfun.kirjaa(
                logitiedosto,
                "Palauta Pettanille puu pettan_{}.tietokanta nimellä {}.".
                format(
                    kansiotyyppi,
                    pettanin_tietokanta[kvak.VOIMASUHTEET[kansiotyyppi][1]]))
            siirretty = False
            for yritys in range(5):
                siirretty = kfun.lataa(
                    True, None, f"pettan_{kansiotyyppi}.tietokanta",
                    "pettankone",
                    pettanin_tietokanta[kvak.VOIMASUHTEET[kansiotyyppi][1]])
                if siirretty:
                    break
            if siirretty:
                logfun.kirjaa(logitiedosto, "Palautettu.")
            else:
                logfun.kirjaa(logitiedosto, "Ei saatu palautettua :<")
            logfun.kirjaa(
                logitiedosto,
                f"Poista pettanilta napattu tiedosto pettan_{kansiotyyppi}.tietokanta"
            )
            os.remove(f"pettan_{kansiotyyppi}.tietokanta")
        else:
            print("Ei saatu kopioitua Pettanilta tiedostotietokantoja")
            logfun.kirjaa(
                logitiedosto,
                "Ei saatu kopioitua Pettanilta tiedostotietokantoja")
    return (1)
예제 #9
0
def paivita_puu(puu, logitiedosto=None):
    '''
	Päivitä paikallisen tietokantatiedoston puu ajan tasalle.
	Rekursiivinen alirutiini funktiolle 'paivita_paikalliset_tietokannat()'
	'''
    # Katsotaan mitä puun kansion alla oikeasti on (tiedostot ja kansiot)
    lok_tied, lok_kans = kfun.kansion_sisalto(puu.hae_nykyinen_polku())
    # Puussa tiedostoja jota ei oikeasti ole olemassa: poista
    poistettavat = []
    for p, puutiedosto in enumerate(puu.tiedostot):
        if puutiedosto.tiedostonimi not in lok_tied:
            logfun.kirjaa(
                logitiedosto,
                f"Tiedostoa {puutiedosto.tiedostonimi} ei enää ole, poista kirjastosta.",
                3)
            poistettavat.append(p)
    if poistettavat:
        poistettavat.reverse()
        for p in poistettavat:
            puu.tiedostot.pop(p)
        poistettavat = []
    # Kansiossa tiedostoja joita ei ole puussa: lisää
    # Kansioss tiedostoja jotka muuttuneet: päivitä
    for paikallinen_tiedosto in lok_tied:
        puuttuu = paikallinen_tiedosto not in [
            a.tiedostonimi for a in puu.tiedostot
        ]
        lok_aika = kfun.tiedoston_aikaleima(
            os.path.join(puu.hae_nykyinen_polku(), paikallinen_tiedosto))
        vanhentunut = any([
            a.lisayspaiva < lok_aika for a in puu.tiedostot
            if a.tiedostonimi == paikallinen_tiedosto
        ])
        # Lisää
        if puuttuu:
            # Biisi
            if puu.tiedostotyyppi is Biisi and kfun.paate(
                    paikallinen_tiedosto)[1] in kvak.MUSATIEDOSTOT:
                tiedosto = Biisi(
                    os.path.join(puu.hae_nykyinen_polku(),
                                 paikallinen_tiedosto))
                logfun.kirjaa(
                    logitiedosto,
                    f"Tiedostoa {paikallinen_tiedosto} ei ole tietokannassa, lisätään.",
                    3)
                puu.tiedostot.append(tiedosto)
            # Yleinen tiedosto
            elif puu.tiedostotyyppi is not Biisi:
                tiedosto = Tiedosto(
                    os.path.join(puu.hae_nykyinen_polku(),
                                 paikallinen_tiedosto))
                logfun.kirjaa(
                    logitiedosto,
                    f"Tiedostoa {paikallinen_tiedosto} ei ole tietokannassa, lisätään.",
                    3)
                puu.tiedostot.append(tiedosto)
        # Päivitä
        elif vanhentunut:
            for i, vanha in enumerate(puu.tiedostot):
                if vanha.tiedostonimi == paikallinen_tiedosto:
                    # Biisi
                    if puu.tiedostotyyppi is Biisi and kfun.paate(
                            paikallinen_tiedosto)[1].lower(
                            ) in kvak.MUSATIEDOSTOT:
                        tiedosto = Biisi(
                            os.path.join(puu.hae_nykyinen_polku(),
                                         paikallinen_tiedosto))
                        if tiedosto.hash != vanha.hash:
                            logfun.kirjaa(
                                logitiedosto,
                                f"Tiedosto {paikallinen_tiedosto} on muuttunut, päivitetään ({lok_aika} < {vanha.lisayspaiva}).",
                                3)
                            puu.tiedostot[i] = tiedosto
                    # Yleinen tiedosto yleisten tiedostojen puussa
                    elif puu.tiedostotyyppi is not Biisi:
                        tiedosto = Tiedosto(
                            os.path.join(puu.hae_nykyinen_polku(),
                                         paikallinen_tiedosto))
                        if tiedosto.hash != vanha.hash:
                            logfun.kirjaa(
                                logitiedosto,
                                f"Tiedostoa {paikallinen_tiedosto} on muuttunut, päivitetään ({lok_aika} < {vanha.lisayspaiva}).",
                                3)
                            puu.tiedostot[i] = tiedosto
                    else:
                        logfun.kirjaa(
                            logitiedosto,
                            f"Tiedostoa {paikallinen_tiedosto} ei tarvitse seurata.",
                            3)
                        puu.tiedostot.pop(i)
                    break
    # Kansiot rekursiivisesti silloin kun aihetta
    for p, puukansio in enumerate([a.kansio for a in puu.alikansiot]):
        # Puussa kansioita joita ei oikeasti ole: poista
        if puukansio not in lok_kans:
            logfun.kirjaa(
                logitiedosto,
                f"Kansiota {puukansio} ei enää ole, poista kirjastosta.", 3)
            poistettavat.append(p)
        # On tietokannassa: sukella sisään ja katso ajantasaisuus
        else:
            # logfun.kirjaa(logitiedosto, f"Tarkistetaan alikansion {puukansio} ajantasaisuus.")
            puu.alikansiot[p] = paivita_puu(puu.alikansiot[p],
                                            logitiedosto=logitiedosto)
    if poistettavat:
        poistettavat.reverse()
        for p in poistettavat:
            puu.alikansiot.pop(p)
    # Tietokannasta puuttuvat kansiot: lisää
    for puuttuvakansio in [
            a for a in lok_kans if a not in [b.kansio for b in puu.alikansiot]
    ]:
        logfun.kirjaa(
            logitiedosto,
            f"Kansiota {puuttuvakansio} ei ole tietokannassa, lisätään.", 3)
        uusipuu = Tiedostopuu(kansio=puuttuvakansio,
                              edellinenkansio=puu,
                              syvennystaso=puu.syvennystaso + 1,
                              tiedostotyyppi=puu.tiedostotyyppi)
        uusipuu.kansoita()
        puu.alikansiot.append(uusipuu)
    # Jos asiat on hassusti niin puussa saattaa olla samoja tiedostoja
    # moneen kertaan, mikä ei suinkaan ole tarkoitus.
    # Laskennan kannalta tämän pitäisi olla funktion alussa, mutta mielummin
    # varmistan että asiat on sitä mitä pitääkin olla kuin että ne tuotetaan fiksusti.
    puu = poista_kaksoiskappaleet(puu)
    return (puu)
    def __init__(self):
        super().__init__()
        self.grid = QtWidgets.QGridLayout()
        self.grid.setSpacing(5)
        self.setStyleSheet(VARITEEMA)

        #-----------------------------------------------------------------------
        # Datat jotka roikkuu messissä ja joita käsitellään

        # Puut (raakadata)
        self.tietokanta = Tiedostopuu()
        self.artistipuu = Artistipuu()
        self.hakutulos_tiedostopuu = Tiedostopuu()
        self.hakutulos_artistipuu = Artistipuu()
        # Varastoi myöhempää käyttöä varten (ei tarvii joka kerta ladata)
        self.aktiivipalvelin = Palvelintiedot()

        # Puut (visualisoitu data)
        self.selauspuu_tiedosto = SelausPuu()
        self.selauspuu_artisti = SelausPuu()
        self.selauspuu_hakutulos_tiedosto = SelausPuu()
        self.selauspuu_hakutulos_artisti = SelausPuu()
        #  Näytä vain yksi selaustyyppi kerrallaan
        self.nakyvat = {
            "selauspuu_tiedosto": True,
            "selauspuu_artisti": False,
            "selauspuu_hakutulos_tiedosto": False,
            "selauspuu_hakutulos_artisti": False,
        }

        # Hakumääritelmä
        self.hakukriteerit = Hakukriteerit()

        #-----------------------------------------------------------------------
        # Suorituslogiikka, säikeiden signalointi

        # Säikeet joissa asioita suoritetaan
        self.thread_tietokantanimet = QtCore.QThread()
        self.thread_tietokantalataus = QtCore.QThread()
        self.thread_biisilataus = QtCore.QThread()

        # Minkä nimisiä tietokantoja palvelimelta löytyy
        self.nimilatain = NimiLatain(self.aktiivipalvelin)
        self.nimilatain.moveToThread(self.thread_tietokantanimet)
        self.nimilatain.signaali_vastaus.connect(self.aseta_tietokantanimet)
        self.nimilatain.signaali_virhe.connect(self.sylje_virhe)

        # Lataa kulloinenkin tietokanta
        self.tietokantalatain = TietokantaLatain(self.aktiivipalvelin)
        self.tietokantalatain.moveToThread(self.thread_tietokantalataus)
        self.tietokantalatain.signaali_vastaus.connect(self.aseta_tietokanta)
        self.tietokantalatain.signaali_virhe.connect(self.sylje_virhe)

        # Biisien lataajaelementti
        self.biisilatain = BiisiLatain(self.aktiivipalvelin)
        self.biisilatain.kohdejuuri = "./"
        self.biisilatain.moveToThread(self.thread_biisilataus)
        self.biisilatain.signaali_valmis.connect(self.siirry_seuraavaan)
        self.biisilatain.signaali_vastaus.connect(self.lisaa_soittolistaan)
        self.biisilatain.signaali_virhe.connect(self.sylje_virhe)

        # Threadialoitukset
        self.thread_tietokantanimet.started.connect(
            self.populoi_tietokantanimet)
        self.thread_tietokantalataus.started.connect(
            self.tietokantalatain.lue_tietokanta)
        self.thread_biisilataus.started.connect(self.biisilatain.lataa)

        #-----------------------------------------------------------------------
        # UI-kälkyttimet

        # Näytä ladattavissa olevat tietokannat pudotusvalikkona
        self.tietokantavaihtoehdot = Pudotusvalikko()
        self.tietokantavaihtoehdot.currentIndexChanged.connect(
            self.vaihda_tietokantaa)
        self.tietokantavaihtoehdot.signaali_vastaus.connect(
            self.paivita_tietokanta)

        # Näytä käytettävissä olevat palvelimet pudotusvalikkona
        self.palvelinvaihtoehdot = Pudotusvalikko()
        self.palvelinvaihtoehdot.currentIndexChanged.connect(
            self.vaihda_palvelinta)
        self.palvelinvaihtoehdot.signaali_vastaus.connect(
            self.paivita_palvelimet)
        self.palvelinvaihtoehdot.addItems(["<palvelimet>"] + list(PALVELIMET))

        # Mikä puunäkymä on tällä hetkellä aktiivisena
        self.aktiivipuu = self.selauspuu_tiedosto

        # Vaihtele tiedostopuun ja artistipuun välillä
        self.nappi_tiedostopuu = QtWidgets.QPushButton()
        self.nappi_artistipuu = QtWidgets.QPushButton()
        self.nappi_tiedostopuu.setStyleSheet(VARITEEMA + "font-weight: bold")
        self.nappi_artistipuu.setStyleSheet(VARITEEMA + "font-weight: bold")
        self.nappi_tiedostopuu.setText("Kansio/Alikansio")
        self.nappi_artistipuu.setText("Artisti/Albumi")
        self.nappi_tiedostopuu.clicked.connect(self.vaihda_tiedostopuuhun)
        self.nappi_artistipuu.clicked.connect(self.vaihda_artistipuuhun)

        # Valinnan tiedot
        self.valintatiedot = Valintatiedot()
        self.selauspuu_tiedosto.selectionModel().selectionChanged.connect(
            self.paivita_tekstiboksi)
        self.selauspuu_artisti.selectionModel().selectionChanged.connect(
            self.paivita_tekstiboksi)
        self.selauspuu_hakutulos_tiedosto.selectionModel(
        ).selectionChanged.connect(self.paivita_tekstiboksi)
        self.selauspuu_hakutulos_artisti.selectionModel(
        ).selectionChanged.connect(self.paivita_tekstiboksi)

        # Latausjono
        self.latauslista = LatausLista(kohdejuuri="./")

        # Latausnappi
        self.latausnappi = QtWidgets.QPushButton()
        self.latausnappi.setStyleSheet(VARITEEMA + "font-weight: bold")
        self.latausnappi.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.latausnappi.setFocusPolicy(QtCore.Qt.NoFocus)
        self.latausnappi.setText("Lataa")
        self.latausnappi.clicked.connect(self.lisaa_valittu_latausjonoon)

        # Hakukenttä
        self.hakukentta = Hakukentta()
        self.hakukentta.returnPressed.connect(self.populoi_hakutuloksilla)

        # Värit kohdilleen
        self.selauspuu_tiedosto.setStyleSheet(VARITEEMA)
        self.selauspuu_artisti.setStyleSheet(VARITEEMA)
        self.selauspuu_hakutulos_tiedosto.setStyleSheet(VARITEEMA)
        self.selauspuu_hakutulos_artisti.setStyleSheet(VARITEEMA)

        #-----------------------------------------------------------------------
        # Asioiden sijainnit

        # Puuselaimet kaikki samaan kohtaan
        self.grid.addWidget(self.selauspuu_tiedosto, *UI_KOOT["selauspuu"])
        self.grid.addWidget(self.selauspuu_artisti, *UI_KOOT["selauspuu"])
        self.grid.addWidget(self.selauspuu_hakutulos_tiedosto,
                            *UI_KOOT["selauspuu"])
        self.grid.addWidget(self.selauspuu_hakutulos_artisti,
                            *UI_KOOT["selauspuu"])

        # Näkymän vaihtonamiskat
        self.grid.addWidget(self.nappi_tiedostopuu,
                            *UI_KOOT["nappi_tiedostopuu"])
        self.grid.addWidget(self.nappi_artistipuu,
                            *UI_KOOT["nappi_artistipuu"])

        # Yläpalkki
        # Etsimiskenttä
        self.grid.addWidget(self.hakukentta, *UI_KOOT["hakukentta"])
        # Tietokantojen nimet pudotusvalikkona
        self.grid.addWidget(self.tietokantavaihtoehdot,
                            *UI_KOOT["tietokantavaihtoehdot"])
        # Palvelinten nimet pudotusvalikkona
        self.grid.addWidget(self.palvelinvaihtoehdot,
                            *UI_KOOT["palvelinvaihtoehdot"])

        # Valinnan tiedot
        self.grid.addWidget(self.valintatiedot, *UI_KOOT["valintatiedot"])

        # Latauslista oikealle alas
        self.grid.addWidget(self.latauslista, *UI_KOOT["latauslista"])

        # Latausnappi
        self.grid.addWidget(self.latausnappi, *UI_KOOT["latausnappi"])

        self.setLayout(self.grid)
        self.setWindowTitle("Uusi musatietokantaselain")
        self.setGeometry(50, 50, 200, 400)

        # Sulkemistoiminto ctrl+q
        self.quitSc = QtWidgets.QShortcut(QtGui.QKeySequence('Ctrl+Q'), self)
        self.quitSc.activated.connect(QtWidgets.QApplication.instance().quit)

        self.alusta()