From 5a1ee4ec3a9e2075ed281340d46195dcd39c8d96 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Mon, 21 May 2012 22:16:50 +0000 Subject: [PATCH 001/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 221 +++++++++++++++++++++-------------------- lang/tomahawk_bg.ts | 174 ++++++++++++++++---------------- lang/tomahawk_ca.ts | 174 ++++++++++++++++---------------- lang/tomahawk_de.ts | 174 ++++++++++++++++---------------- lang/tomahawk_en.ts | 174 ++++++++++++++++---------------- lang/tomahawk_es.ts | 174 ++++++++++++++++---------------- lang/tomahawk_fr.ts | 174 ++++++++++++++++---------------- lang/tomahawk_ja.ts | 174 ++++++++++++++++---------------- lang/tomahawk_pl.ts | 174 ++++++++++++++++---------------- lang/tomahawk_pt_BR.ts | 174 ++++++++++++++++---------------- lang/tomahawk_ru.ts | 174 ++++++++++++++++---------------- lang/tomahawk_sv.ts | 174 ++++++++++++++++---------------- lang/tomahawk_tr.ts | 174 ++++++++++++++++---------------- lang/tomahawk_zh_CN.ts | 174 ++++++++++++++++---------------- lang/tomahawk_zh_TW.ts | 174 ++++++++++++++++---------------- 15 files changed, 1330 insertions(+), 1327 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index c8d84f64b..7ff72da0d 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. - + This collection is currently empty. المجموعة فارغة حاليا. - + Sorry, your filter '%1' did not match any results. نتأسف، نظام البحث لم يجد شيئا تحت عنوان '%1'. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection مجموعتي الخاصة - + Collection of %1 مجموعة %1 @@ -661,17 +661,80 @@ connect and stream from you? + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate played %1 by you - + سمعت %1 played %1 by %2 - + %2 سمع %1 @@ -679,12 +742,12 @@ connect and stream from you? played %1 by you - + سمعت %1 played %1 by %2 - + %2 سمع %1 @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you أنت - + All tracks by %1 on album %2 جميع أغاني %1 في البوم %2 - + All tracks by %1 جميع أغاني %1 @@ -808,7 +871,8 @@ connect and stream from you? No Proxy Hosts: (Overrides system proxy) - + لا مضيف للوكيل: +(تجاوز وكيل النظام) @@ -826,7 +890,7 @@ connect and stream from you? %n year(s) ago - + منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات @@ -1419,7 +1483,7 @@ connect and stream from you? Watch for changes - + إنتبه للتغييرات @@ -1469,32 +1533,32 @@ connect and stream from you? Internet Services - + خدمات الانترنت Install from file... - + تثبيت من ملف... Filter by capability: - + تصفية حسب القدرة: Static Host Name: - + اسم مضيف ثابت: Static Port: - + بوابة ثابتة: Proxy Settings... - + إعدادات الوسيط... @@ -1621,17 +1685,17 @@ connect and stream from you? Failed - + فشلت Success - + نجاح Could not contact server - + لم أستطيع الإتصال بالخادم @@ -1683,7 +1747,7 @@ connect and stream from you? Connect to your Twitter followers. - + تواصل مع أصدقائك على تويتر. @@ -1706,7 +1770,7 @@ connect and stream from you? Authenticate - + وثق @@ -1755,7 +1819,7 @@ You may wish to try re-authenticating. Send Message! - + إرسل رسالة! @@ -1776,19 +1840,21 @@ You may wish to try re-authenticating. Your saved credentials could not be loaded. You may wish to try re-authenticating. - + لم نستطيع تحميل بياناتك المحفوظة. +قد ترغب بمعاودة التصديق. Your saved credentials could not be verified. You may wish to try re-authenticating. - + لم نستطيع التحقق من بياناتك المحفوظة. +قد ترغب بمعاودة التصديق. There was an error posting your status -- sorry! - + عذراً... حصل خطأ في تسجيل رسالتك! @@ -1998,7 +2064,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3177,73 +3243,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - الفنان - - - - Title - - - - - Album - البوم - - - - Track - اغنية - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3272,59 +3275,59 @@ enter the displayed PIN number here: TreeModel - + Name - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Composer - + All Artists جميع الفنانين - - + + My Collection - - + + Collection of %1 diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 71b43078c..d44c74a84 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. След като приключи сканирането на музикалната ти колекция, ще откриеш музиката си тук. - + This collection is currently empty. Базата данни с песни е празна. - + Sorry, your filter '%1' did not match any results. Съжалявам. Твоят филтър '%1' не върна никакъв резултат. @@ -338,12 +338,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Моята колекция - + Collection of %1 Колекцията на %1 @@ -665,6 +665,69 @@ Tomahaw създаде доклад относно това и изпращай Нови албуми + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -699,22 +762,22 @@ Tomahaw създаде доклад относно това и изпращай PlaylistModel - + A playlist by %1, created %2 Списък - създател %1, от %2 - + you ти - + All tracks by %1 on album %2 Всички песни от %1, от албум %2 - + All tracks by %1 Всички песни от %1 @@ -2012,7 +2075,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3197,73 +3260,10 @@ enter the displayed PIN number here: Никога не си слушал %1 преди - - TrackModel - - - Artist - Артист - - - - Title - Заглавие - - - - Album - Албум - - - - Track - Номер - - - - Duration - Продължителност - - - - Bitrate - Качество - - - - Age - Възраст - - - - Year - Година - - - - Size - Размер - - - - Origin - Произход - - - - Score - Популярност - - - - Composer - Композитор - - TrackView - + Sorry, your filter '%1' did not match any results. Съжалявам, твоят филтър %1 не върна никакъв резултат. @@ -3292,59 +3292,59 @@ enter the displayed PIN number here: TreeModel - + Name Име - + Duration Продължителност - + Bitrate Качество - + Age Възраст - + Year Година - + Size Размер - + Origin Произход - + Composer Композитор - + All Artists Всички артисти - - + + My Collection Моята колекция - - + + Collection of %1 Колекцията на %1 diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 9c075f80e..62a19456b 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Després d'escanejar la vostra col·lecció musical, aquí trobareu les cançons afegides últimament. - + This collection is currently empty. Aquesta col·lecció es troba buida actualment. - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection La meva Col·lecció - + Collection of %1 Col·lecció de %1 @@ -661,6 +661,69 @@ connect and stream from you? Nous llançaments + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Una llista de reproduccó de %1, creada %2 - + you - + All tracks by %1 on album %2 Totes les cançons de %1 a l'àlbum %2 - + All tracks by %1 Totes les cançons de %1 @@ -2006,7 +2069,7 @@ Canvieu els filtres o intenteu-ho de nou. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3188,73 +3251,10 @@ introduïu el PIN aquí: No heu escoltat mai %1 abans. - - TrackModel - - - Artist - Artista - - - - Title - Títol - - - - Album - Àlbum - - - - Track - Cançó - - - - Duration - Durada - - - - Bitrate - Bitrate - - - - Age - Edat - - - - Year - Any - - - - Size - Mida - - - - Origin - Origen - - - - Score - Puntuació - - - - Composer - Compositor - - TrackView - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -3283,59 +3283,59 @@ introduïu el PIN aquí: TreeModel - + Name Nom - + Duration Durada - + Bitrate Bitrate - + Age Edat - + Year Any - + Size Mida - + Origin Origen - + Composer Compositor - + All Artists Tots els Artistes - - + + My Collection La meva Col·lecció - - + + Collection of %1 Col·lecció de %1 diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index d1ffb4e3c..d4c523de8 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Nachdem Tomahawk deine Sammlung durchsucht hat siehst du deine Lieder hier. - + This collection is currently empty. Diese Sammlung is momentan leer. - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Meine Sammlung - + Collection of %1 Sammlung von %1 @@ -661,6 +661,69 @@ connect and stream from you? Neuerscheinungen + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Eine Playliste von %1, erstellt %2 - + you dir - + All tracks by %1 on album %2 Alle Lieder von %1 auf dem Album %2 - + All tracks by %1 Alle Lieder von %1 @@ -2001,7 +2064,7 @@ Bitte ändere den Filter oder versuche es erneut. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3183,73 +3246,10 @@ Tomahawk auf Twitter's Website authentifiziert hast: - - TrackModel - - - Artist - Künstler - - - - Title - Titel - - - - Album - Album - - - - Track - Titel - - - - Duration - Spieldauer - - - - Bitrate - Bitrate - - - - Age - Alter - - - - Year - Jahr - - - - Size - Größe - - - - Origin - Quelle - - - - Score - Wertung - - - - Composer - Komponist - - TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3278,59 +3278,59 @@ Tomahawk auf Twitter's Website authentifiziert hast: TreeModel - + Name Name - + Duration Dauer - + Bitrate Bitrate - + Age Alter - + Year Jahr - + Size Größe - + Origin Quelle - + Composer Komponist - + All Artists Alle Künstler - - + + My Collection Meine Sammlung - - + + Collection of %1 Sammlung von %1 diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 2d9b5acf8..3d24dedbb 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. This collection is currently empty. - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -338,12 +338,12 @@ connect and stream from you? CollectionFlatModel - + My Collection My Collection - + Collection of %1 Collection of %1 @@ -662,6 +662,69 @@ connect and stream from you? New Releases + + PlayableModel + + + Artist + Artist + + + + Title + Title + + + + Composer + Composer + + + + Album + Album + + + + Track + Track + + + + Duration + Duration + + + + Bitrate + Bitrate + + + + Age + Age + + + + Year + Year + + + + Size + Size + + + + Origin + Origin + + + + Score + Score + + PlaylistItemDelegate @@ -696,22 +759,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 A playlist by %1, created %2 - + you you - + All tracks by %1 on album %2 All tracks by %1 on album %2 - + All tracks by %1 All tracks by %1 @@ -2007,7 +2070,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3189,73 +3252,10 @@ enter the displayed PIN number here: You've never listened to %1 before. - - TrackModel - - - Artist - Artist - - - - Title - Title - - - - Album - Album - - - - Track - Track - - - - Duration - Duration - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Year - - - - Size - Size - - - - Origin - Origin - - - - Score - Score - - - - Composer - Composer - - TrackView - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -3284,59 +3284,59 @@ enter the displayed PIN number here: TreeModel - + Name Name - + Duration Duration - + Bitrate Bitrate - + Age Age - + Year Year - + Size Size - + Origin Origin - + Composer Composer - + All Artists All Artists - - + + My Collection My Collection - - + + Collection of %1 Collection of %1 diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 797b84c42..73a09ae35 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Tras haber escaneado su colección aquí encontrará las últimas pistas añadidas. - + This collection is currently empty. Esta colección está vacía. - + Sorry, your filter '%1' did not match any results. Tu filtro '%1' no reportó ningún resultado. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Mi colección - + Collection of %1 Colección de %1 @@ -661,6 +661,69 @@ connect and stream from you? Últimas novedades + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Una lista de reproducción de %1, creada %2 - + you usted - + All tracks by %1 on album %2 Todas las pistas de %1 en el álbum %2 - + All tracks by %1 Todas las pistas de %1 @@ -2005,7 +2068,7 @@ Por favor, cambie los filtros o inténtelo de nuevo. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3187,73 +3250,10 @@ introduzca su número PIN aquí: Nunca ha escuchado %1 antes. - - TrackModel - - - Artist - Artista - - - - Title - Título - - - - Album - Álbum - - - - Track - Tema - - - - Duration - Duración - - - - Bitrate - Bitrate - - - - Age - Edad - - - - Year - Año - - - - Size - Tamaño - - - - Origin - Origen - - - - Score - Puntuación - - - - Composer - Compositor - - TrackView - + Sorry, your filter '%1' did not match any results. Lo siento, tu filtro '%1' no ha encontrado resultados. @@ -3282,59 +3282,59 @@ introduzca su número PIN aquí: TreeModel - + Name Nombre - + Duration Duración - + Bitrate Bitrate - + Age Edad - + Year Año - + Size Tamaño - + Origin Origen - + Composer Compositor - + All Artists Todos los artistas - - + + My Collection Mi colección - - + + Collection of %1 Colección de %1 diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 85d926132..4a555f1fe 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -197,17 +197,17 @@ se connecter et streamer depuis chez vous ? ArtistView - + After you have scanned your music collection you will find your tracks right here. Après avoir scanné votre collection musicale, vous trouverez vos pistes ici. - + This collection is currently empty. La collection est vide actuellement. - + Sorry, your filter '%1' did not match any results. Désolé, votre filtre '%1' ne correspond à aucun résultat @@ -338,12 +338,12 @@ se connecter et streamer depuis chez vous ? CollectionFlatModel - + My Collection Ma Collection - + Collection of %1 Collection de %1 @@ -662,6 +662,69 @@ se connecter et streamer depuis chez vous ? Nouveautés + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -696,22 +759,22 @@ se connecter et streamer depuis chez vous ? PlaylistModel - + A playlist by %1, created %2 Une liste de lecture par %1, créée %2 - + you vous - + All tracks by %1 on album %2 Toutes les pistes par %1 sur l'album %2 - + All tracks by %1 Toutes les pistes par %1 @@ -2007,7 +2070,7 @@ Veuillez changer les filtres et essayez de nouveau. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3189,73 +3252,10 @@ saisissez le numéro PIN ici : Vous n'avez encore jamais écouté %1. - - TrackModel - - - Artist - Artiste - - - - Title - Titre - - - - Album - Album - - - - Track - Piste - - - - Duration - Durée - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Année - - - - Size - Taille - - - - Origin - Origine - - - - Score - Score - - - - Composer - Compositeur - - TrackView - + Sorry, your filter '%1' did not match any results. Désolé, votre filtre '%1' ne correspond à aucun résultat @@ -3284,59 +3284,59 @@ saisissez le numéro PIN ici : TreeModel - + Name Nom - + Duration Durée - + Bitrate Bitrate - + Age Age - + Year Année - + Size Taille - + Origin Origine - + Composer Compositeur - + All Artists Tous les artistes - - + + My Collection Ma Collection - - + + Collection of %1 Collection de %1 diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index b976c2a9b..49db53065 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. このコレクションは現在空です。 - + Sorry, your filter '%1' did not match any results. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection - + Collection of %1 %1のコレクション @@ -661,6 +661,69 @@ connect and stream from you? + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you - + All tracks by %1 on album %2 - + All tracks by %1 @@ -1999,7 +2062,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3178,73 +3241,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - - - - - Title - - - - - Album - - - - - Track - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3273,59 +3273,59 @@ enter the displayed PIN number here: TreeModel - + Name - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Composer - + All Artists - - + + My Collection - - + + Collection of %1 diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 7722edbde..5d1a6c891 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Po zeskanowaniu swojej kolekcji muzycznej utwory znajdziesz w tym miejscu. - + This collection is currently empty. Ta kolekcja jest aktualnie pusta. - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie pasuje do żadnych wyników. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Moja Kolekcja - + Collection of %1 Kolekcja %1 @@ -661,6 +661,69 @@ connect and stream from you? Nowe Wydania + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 %1 lista, utworzona %2 - + you Twoja - + All tracks by %1 on album %2 Wszystkie piosenki %1 z albumu %2 - + All tracks by %1 Wszystkie piosenki %1 @@ -2003,7 +2066,7 @@ Proszę zmienić filtry lub spróbować ponownie. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3183,73 +3246,10 @@ wprowadź pokazany numer PIN tutaj: - - TrackModel - - - Artist - Artysta - - - - Title - Tytuł - - - - Album - Album - - - - Track - Utwór - - - - Duration - Czas trwania - - - - Bitrate - Bitrate - - - - Age - Wiek - - - - Year - Rok - - - - Size - Rozmiar - - - - Origin - Pochodzenie - - - - Score - Punktacja - - - - Composer - Kompozytor - - TrackView - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie dopasował żadnych wyników. @@ -3278,59 +3278,59 @@ wprowadź pokazany numer PIN tutaj: TreeModel - + Name Nazwa - + Duration Czas trwania - + Bitrate Bitrate - + Age Wiek - + Year Rok - + Size Rozmiar - + Origin Pochodzenie - + Composer Kompozytor - + All Artists Wszyscy Artyści - - + + My Collection Moja Kolekcja - - + + Collection of %1 Kolekcja %1 diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 659d0c6bf..3a27083af 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Depois que você escanear a sua biblioteca musical você encontrará aqui as suas faixas. - + This collection is currently empty. Essa biblioteca está vazia. - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Minha biblioteca - + Collection of %1 Biblioteca de %1 @@ -661,6 +661,69 @@ connect and stream from you? + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Uma lista de reprodução de %1, criada %2 - + you você - + All tracks by %1 on album %2 Todas as faixas de %1 no álbum %2 - + All tracks by %1 Todas as faixas de %1 @@ -2002,7 +2065,7 @@ Por favor, mude os filtros ou tente novamente. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3182,73 +3245,10 @@ colocar o número PIN mostrado aqui: - - TrackModel - - - Artist - Artista - - - - Title - Título - - - - Album - Álbum - - - - Track - Faixa - - - - Duration - Duração - - - - Bitrate - Taxa de bits - - - - Age - Idate - - - - Year - Ano - - - - Size - Tamanho - - - - Origin - Origem - - - - Score - Pontuação - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -3277,59 +3277,59 @@ colocar o número PIN mostrado aqui: TreeModel - + Name Nome - + Duration Duração - + Bitrate Taxa de bits - + Age Idate - + Year Ano - + Size Tamanho - + Origin Origem - + Composer - + All Artists Todos artistas - - + + My Collection Minha biblioteca - - + + Collection of %1 Biblioteca de %1 diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 3463de29b..38aa55036 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. После сканирования вашей музыкальной коллекции вы найдете свои песни тут. - + This collection is currently empty. Коллекция пуста. - + Sorry, your filter '%1' did not match any results. К сожалению, '%1' фильтр не найдено ни одного результата. @@ -338,12 +338,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Моя Коллекция - + Collection of %1 Коллекция %1 @@ -662,6 +662,69 @@ connect and stream from you? Новые релизы + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -696,22 +759,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 Плейлист %1 создан %2 - + you Вы - + All tracks by %1 on album %2 Все песни %1 альбома %2 - + All tracks by %1 Все песни %1 @@ -2004,7 +2067,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3183,73 +3246,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - Исполнитель - - - - Title - Название - - - - Album - Альбом - - - - Track - Песня - - - - Duration - Длительность - - - - Bitrate - Битрей - - - - Age - Возраст - - - - Year - Год - - - - Size - Размер - - - - Origin - Расположение - - - - Score - Проиграно - - - - Composer - Композитор - - TrackView - + Sorry, your filter '%1' did not match any results. Ваш поиск '%1' недал результатов. @@ -3278,59 +3278,59 @@ enter the displayed PIN number here: TreeModel - + Name Имя - + Duration Длительность - + Bitrate Битрей - + Age Возраст - + Year Год - + Size Размер - + Origin Расположение - + Composer Композитор - + All Artists Все исполнители - - + + My Collection Моя коллекция - - + + Collection of %1 Коллекция из %1 diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index afa6f9f9c..22b2fa6b9 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda låtar här. - + This collection is currently empty. Denna samling är tom. - + Sorry, your filter '%1' did not match any results. Tyvärr, ditt filter "%1" matchade inte några resultat. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Min samling - + Collection of %1 Samling av %1 @@ -661,6 +661,69 @@ connect and stream from you? + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 En spellista av %1, skapad %2 - + you dig - + All tracks by %1 on album %2 Alla spår av %1 från albumet %2 - + All tracks by %1 Alla spår av %1 @@ -1998,7 +2061,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3177,73 +3240,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - Artist - - - - Title - Titel - - - - Album - Album - - - - Track - Spår - - - - Duration - Speltid - - - - Bitrate - Bitfrekvens - - - - Age - Ålder - - - - Year - År - - - - Size - Storlek - - - - Origin - Källa - - - - Score - Betyg - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3272,59 +3272,59 @@ enter the displayed PIN number here: TreeModel - + Name Namn - + Duration Speltid - + Bitrate Bitfrekvens - + Age Ålder - + Year År - + Size Storlek - + Origin Källa - + Composer - + All Artists Alla artister - - + + My Collection Min samling - - + + Collection of %1 Samling av %1 diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 944d2855a..3c93fbebe 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Müzik koleksiyonunuzu taradıktan parçalarınız tam burada bulacaksınız. - + This collection is currently empty. Bu koleksiyon şu anda boş. - + Sorry, your filter '%1' did not match any results. Üzgünüm, '%1' filtresi hiçbir sonuç getirmedi. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection Koleksiyonum - + Collection of %1 %1 Koleksiyonu @@ -661,6 +661,69 @@ connect and stream from you? + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you - + All tracks by %1 on album %2 - + All tracks by %1 @@ -1997,7 +2060,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3176,73 +3239,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - - - - - Title - - - - - Album - - - - - Track - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3271,59 +3271,59 @@ enter the displayed PIN number here: TreeModel - + Name - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Composer - + All Artists - - + + My Collection - - + + Collection of %1 diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index e2c0b64a7..b32a570aa 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. 此收藏目前为空 - + Sorry, your filter '%1' did not match any results. 抱歉,你的过滤条件 '%1' 未匹配任何结果 @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection - + Collection of %1 @@ -661,6 +661,69 @@ connect and stream from you? + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you - + All tracks by %1 on album %2 - + All tracks by %1 @@ -1997,7 +2060,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3176,73 +3239,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - - - - - Title - - - - - Album - - - - - Track - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3271,59 +3271,59 @@ enter the displayed PIN number here: TreeModel - + Name - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Composer - + All Artists - - + + My Collection - - + + Collection of %1 diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index b50ec223d..54e1a0e02 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. 當您掃描您的音樂收藏,您將在這裡找到您的曲目。 - + This collection is currently empty. 目前這個收藏是空的。 - + Sorry, your filter '%1' did not match any results. @@ -337,12 +337,12 @@ connect and stream from you? CollectionFlatModel - + My Collection 我的收藏 - + Collection of %1 @@ -661,6 +661,69 @@ connect and stream from you? 新版本 + + PlayableModel + + + Artist + + + + + Title + + + + + Composer + + + + + Album + + + + + Track + + + + + Duration + + + + + Bitrate + + + + + Age + + + + + Year + + + + + Size + + + + + Origin + + + + + Score + + + PlaylistItemDelegate @@ -695,22 +758,22 @@ connect and stream from you? PlaylistModel - + A playlist by %1, created %2 - + you - + All tracks by %1 on album %2 - + All tracks by %1 @@ -1997,7 +2060,7 @@ Please change the filters or try again. Tomahawk::DynamicWidget - + Station ran out of tracks! Try tweaking the filters for a new set of songs to play. @@ -3176,73 +3239,10 @@ enter the displayed PIN number here: - - TrackModel - - - Artist - 演出者 - - - - Title - 標題 - - - - Album - 專輯 - - - - Track - 曲目 - - - - Duration - 長度 - - - - Bitrate - 比特率 - - - - Age - 年代 - - - - Year - - - - - Size - - - - - Origin - - - - - Score - - - - - Composer - - - TrackView - + Sorry, your filter '%1' did not match any results. @@ -3271,60 +3271,60 @@ enter the displayed PIN number here: TreeModel - + Name 名稱 - + Duration 長度 - + Bitrate - + Age 年代 - + Year - + Size - + Origin - + Composer - + All Artists - - + + My Collection 我的收藏 - - + + Collection of %1 From d44028a2af36cf07e8848da4cc09ac39a6e71d25 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 02:34:33 +0200 Subject: [PATCH 002/433] * AlbumModel items shouldn't be editable. --- src/libtomahawk/playlist/AlbumModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/AlbumModel.cpp b/src/libtomahawk/playlist/AlbumModel.cpp index eae9d2b64..649e92258 100644 --- a/src/libtomahawk/playlist/AlbumModel.cpp +++ b/src/libtomahawk/playlist/AlbumModel.cpp @@ -155,7 +155,7 @@ AlbumModel::flags( const QModelIndex& index ) const Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index ); if ( index.isValid() && index.column() == 0 ) - return Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; else return defaultFlags; } From 530d9d7e5fcb8eb8809927bb986447684b3a3a94 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 08:01:14 +0200 Subject: [PATCH 003/433] * Fixed systray menu not working. --- src/TomahawkTrayIcon.cpp | 17 +++++++++-------- src/TomahawkTrayIcon.h | 3 +-- src/libtomahawk/ActionCollection.cpp | 12 ++++++------ src/libtomahawk/ActionCollection.h | 2 +- src/libtomahawk/audio/AudioEngine.cpp | 2 +- src/libtomahawk/audio/AudioEngine.h | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/TomahawkTrayIcon.cpp b/src/TomahawkTrayIcon.cpp index 7fd9955ed..08abee130 100644 --- a/src/TomahawkTrayIcon.cpp +++ b/src/TomahawkTrayIcon.cpp @@ -49,7 +49,8 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu = new QMenu(); setContextMenu( m_contextMenu ); - m_stopContinueAfterTrackAction = new QAction( tr( "&Stop Playback after current Track" ), this ); + m_stopContinueAfterTrackAction = new QAction( this ); + onStopContinueAfterTrackChanged(); ActionCollection *ac = ActionCollection::instance(); m_contextMenu->addAction( ac->getAction( "playPause" ) ); @@ -61,7 +62,7 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu->addSeparator(); m_contextMenu->addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) ); - connect( m_stopContinueAfterTrackAction, SIGNAL( triggered(bool) ), this, SLOT( stopContinueAfterTrackActionTriggered() ) ); + connect( m_stopContinueAfterTrackAction, SIGNAL( triggered() ), SLOT( stopContinueAfterTrackActionTriggered() ) ); #ifdef Q_WS_MAC // On mac you can close the windows while leaving the app open. We then need a way to show the main window again @@ -78,10 +79,10 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( setResult( Tomahawk::result_ptr ) ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlay() ) ); - connect( AudioEngine::instance(), SIGNAL( resumed() ), this, SLOT( onResume() ) ); - connect( AudioEngine::instance(), SIGNAL( stopped() ), this, SLOT( onStop() ) ); - connect( AudioEngine::instance(), SIGNAL( paused() ), this, SLOT( onPause() ) ); - connect( AudioEngine::instance(), SIGNAL( stopAfterTrack_changed() ) , this, SLOT( stopContinueAfterTrack_StatusChanged() ) ); + connect( AudioEngine::instance(), SIGNAL( resumed() ), SLOT( onResume() ) ); + connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onStop() ) ); + connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( onPause() ) ); + connect( AudioEngine::instance(), SIGNAL( stopAfterTrackChanged() ), SLOT( onStopContinueAfterTrackChanged() ) ); connect( &m_animationTimer, SIGNAL( timeout() ), SLOT( onAnimationTimer() ) ); connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), SLOT( onActivated( QSystemTrayIcon::ActivationReason ) ) ); @@ -236,7 +237,7 @@ TomahawkTrayIcon::onPlay() { m_stopContinueAfterTrackAction->setEnabled( true ); onResume(); - stopContinueAfterTrack_StatusChanged(); + onStopContinueAfterTrackChanged(); } @@ -256,7 +257,7 @@ TomahawkTrayIcon::onResume() void -TomahawkTrayIcon::stopContinueAfterTrack_StatusChanged() +TomahawkTrayIcon::onStopContinueAfterTrackChanged() { if ( !AudioEngine::instance()->currentTrack().isNull() ) { diff --git a/src/TomahawkTrayIcon.h b/src/TomahawkTrayIcon.h index d1504e835..d1c73f41c 100644 --- a/src/TomahawkTrayIcon.h +++ b/src/TomahawkTrayIcon.h @@ -49,8 +49,7 @@ private slots: void onStop(); void onResume(); - void stopContinueAfterTrack_StatusChanged(); - + void onStopContinueAfterTrackChanged(); void stopContinueAfterTrackActionTriggered(); void menuAboutToShow(); diff --git a/src/libtomahawk/ActionCollection.cpp b/src/libtomahawk/ActionCollection.cpp index e69f723bd..bc6908e30 100644 --- a/src/libtomahawk/ActionCollection.cpp +++ b/src/libtomahawk/ActionCollection.cpp @@ -32,7 +32,7 @@ ActionCollection* ActionCollection::instance() } -ActionCollection::ActionCollection( QObject *parent ) +ActionCollection::ActionCollection( QObject* parent ) : QObject( parent ) { s_instance = this; @@ -79,11 +79,11 @@ ActionCollection::initActions() m_actionCollection[ "quit" ] = new QAction( tr( "&Quit" ), this ); // connect actions to AudioEngine -// AudioEngine *ae = AudioEngine::instance(); -// connect( m_actionCollection[ "playPause" ], SIGNAL( triggered() ), ae, SLOT( playPause() ), Qt::UniqueConnection ); -// connect( m_actionCollection[ "stop" ], SIGNAL( triggered() ), ae, SLOT( stop() ), Qt::UniqueConnection ); -// connect( m_actionCollection[ "previousTrack" ], SIGNAL( triggered() ), ae, SLOT( previous() ), Qt::UniqueConnection ); -// connect( m_actionCollection[ "nextTrack" ], SIGNAL( triggered() ), ae, SLOT( next() ), Qt::UniqueConnection ); + AudioEngine *ae = AudioEngine::instance(); + connect( m_actionCollection[ "playPause" ], SIGNAL( triggered() ), ae, SLOT( playPause() ), Qt::UniqueConnection ); + connect( m_actionCollection[ "stop" ], SIGNAL( triggered() ), ae, SLOT( stop() ), Qt::UniqueConnection ); + connect( m_actionCollection[ "previousTrack" ], SIGNAL( triggered() ), ae, SLOT( previous() ), Qt::UniqueConnection ); + connect( m_actionCollection[ "nextTrack" ], SIGNAL( triggered() ), ae, SLOT( next() ), Qt::UniqueConnection ); } diff --git a/src/libtomahawk/ActionCollection.h b/src/libtomahawk/ActionCollection.h index 2eb327622..378b13cba 100644 --- a/src/libtomahawk/ActionCollection.h +++ b/src/libtomahawk/ActionCollection.h @@ -38,7 +38,7 @@ public: static ActionCollection* instance(); - ActionCollection( QObject *parent); + ActionCollection( QObject *parent ); ~ActionCollection(); void initActions(); diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index dc882e46b..5be4c1adc 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -783,7 +783,7 @@ AudioEngine::setStopAfterTrack( const query_ptr& query ) if ( m_stopAfterTrack != query ) { m_stopAfterTrack = query; - emit stopAfterTrack_changed(); + emit stopAfterTrackChanged(); } } diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index ce14a397d..c5e3aeac8 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -109,7 +109,7 @@ signals: void paused(); void resumed(); - void stopAfterTrack_changed(); + void stopAfterTrackChanged(); void seeked( qint64 ms ); From 95dccb8cf9ed099203924923feaf41964cc96bd1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 08:07:07 +0200 Subject: [PATCH 004/433] * Improved resolving: be more careful when it comes to result similarity. --- src/libtomahawk/Pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index 205a9e7aa..c3fd08114 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -286,7 +286,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) m_rids.insert( r->id(), r ); } - if ( q->playable() && !q->isFullTextQuery() ) + if ( q->solved() && !q->isFullTextQuery() ) { setQIDState( q, 0 ); return; From 7ffb3b2fef3a7538650d7daebb96228a88f1a30d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 10:41:12 +0200 Subject: [PATCH 005/433] * Fixed logic error in DbCmd_TrackAttributes. --- .../database/DatabaseCommand_TrackAttributes.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp b/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp index b41e55fe4..48a313148 100644 --- a/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp +++ b/src/libtomahawk/database/DatabaseCommand_TrackAttributes.cpp @@ -49,7 +49,6 @@ void DatabaseCommand_TrackAttributes::exec( DatabaseImpl* lib ) PairList results; if ( !m_ids.isEmpty() ) { - foreach ( const QID id, m_ids ) { query.prepare( "SELECT v FROM track_attributes WHERE id = ? AND k = ?" ); @@ -58,11 +57,13 @@ void DatabaseCommand_TrackAttributes::exec( DatabaseImpl* lib ) if ( query.exec() ) results.append( QPair< QID, QString >( id, query.value( 0 ).toString() ) ); } - } else { + } + else + { query.prepare( "SELECT id, v FROM track_attributes WHERE k = ?" ); query.bindValue( 0, k ); query.exec(); - while ( !query.next() ) + while ( query.next() ) { results.append( QPair< QID, QString >( query.value( 0 ).toString(), query.value( 1 ).toString() ) ); } From b1904b877e42967240dd41c923b7d7b603b8f86b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 10:41:37 +0200 Subject: [PATCH 006/433] * Cleaner code in AudioEngine. --- src/libtomahawk/audio/AudioEngine.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 5be4c1adc..57b22ac2b 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -791,16 +791,15 @@ AudioEngine::setStopAfterTrack( const query_ptr& query ) void AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) { - Tomahawk::result_ptr lastTrack = m_currentTrack; - if ( !lastTrack.isNull() ) + if ( !m_currentTrack.isNull() ) { if ( m_state != Error && TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening ) { - DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( lastTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed ); + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_currentTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed ); Database::instance()->enqueue( QSharedPointer(cmd) ); } - emit finished( lastTrack ); + emit finished( m_currentTrack ); } m_currentTrack = result; From 3f5d219549399bea5a0a22f18ad4d1d140e57f27 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 10:41:58 +0200 Subject: [PATCH 007/433] * Fixed sorting order when retrieving playback history. --- src/libtomahawk/database/DatabaseCommand_TrackStats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp b/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp index a85397dee..b918a4852 100644 --- a/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp +++ b/src/libtomahawk/database/DatabaseCommand_TrackStats.cpp @@ -56,7 +56,7 @@ DatabaseCommand_TrackStats::exec( DatabaseImpl* dbi ) query.prepare( "SELECT * " "FROM playback_log " - "WHERE track = ?" ); + "WHERE track = ? ORDER BY playtime ASC" ); query.addBindValue( trkid ); query.exec(); } From 2ee66a3cda6d1ced6d66955f81513218657407e9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 10:43:39 +0200 Subject: [PATCH 008/433] * Allow to locally import Last.fm playback history. Works but needs discussion. --- src/accounts/lastfm/LastFmConfig.cpp | 99 ++++++++++++++++--- src/accounts/lastfm/LastFmConfig.h | 7 +- src/accounts/lastfm/LastFmConfig.ui | 16 ++- .../database/DatabaseCommand_LogPlayback.cpp | 49 +++++---- .../database/DatabaseCommand_LogPlayback.h | 12 +++ 5 files changed, 152 insertions(+), 31 deletions(-) diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index d364d7ba4..a0e5caa6b 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -17,15 +17,20 @@ */ #include "LastFmConfig.h" +#include "ui_LastFmConfig.h" #include "LastFmAccount.h" -#include -#include "ui_LastFmConfig.h" +#include "database/Database.h" +#include "database/DatabaseCommand_LogPlayback.h" +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" #include "lastfm/ws.h" +#include "lastfm/User" #include "lastfm/XmlQuery" using namespace Tomahawk::Accounts; + LastFmConfig::LastFmConfig( LastFmAccount* account ) : QWidget( 0 ) , m_account( account ) @@ -33,18 +38,17 @@ LastFmConfig::LastFmConfig( LastFmAccount* account ) m_ui = new Ui_LastFmConfig; m_ui->setupUi( this ); + m_ui->progressBar->hide(); + m_ui->username->setText( m_account->username() ); m_ui->password->setText( m_account->password() ); m_ui->enable->setChecked( m_account->scrobble() ); - connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), this, SLOT( testLogin( bool ) ) ); + connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), SLOT( testLogin() ) ); + connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) ); - connect( m_ui->username, SIGNAL( textChanged( QString ) ), this, SLOT( enableButton() ) ); - connect( m_ui->password, SIGNAL( textChanged( QString ) ), this, SLOT( enableButton() ) ); - -// #ifdef Q_WS_MAC // FIXME -// m_ui->testLogin->setVisible( false ); -// #endif + connect( m_ui->username, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); + connect( m_ui->password, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); } @@ -70,10 +74,10 @@ LastFmConfig::username() const void -LastFmConfig::testLogin(bool ) +LastFmConfig::testLogin() { m_ui->testLogin->setEnabled( false ); - m_ui->testLogin->setText( "Testing..." ); + m_ui->testLogin->setText( tr( "Testing..." ) ); QString authToken = TomahawkUtils::md5( ( m_ui->username->text().toLower() + TomahawkUtils::md5( m_ui->password->text().toUtf8() ) ).toUtf8() ); @@ -100,6 +104,79 @@ LastFmConfig::enableButton() } +void +LastFmConfig::loadHistory( int page ) +{ + if ( page == 1 ) + { + m_ui->importHistory->setText( tr( "Importing History..." ) ); + m_ui->importHistory->setEnabled( false ); + + m_ui->progressBar->show(); + } + + QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, page ); + connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) ); +} + + +void +LastFmConfig::onHistoryLoaded() +{ + bool finished = false; + QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); + + try + { + lastfm::XmlQuery lfm = reply->readAll(); + + foreach ( lastfm::XmlQuery e, lfm.children( "track" ) ) + { + tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt(); + Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false ); + uint timeStamp = e["date"].attribute( "uts" ).toUInt(); + + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, timeStamp ); + Database::instance()->enqueue( QSharedPointer(cmd) ); + } + + if ( !lfm.children( "recenttracks" ).isEmpty() ) + { + lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first(); + + int page = stats.attribute( "page" ).toInt(); + int total = stats.attribute( "totalPages" ).toInt(); + tDebug() << "page:" << page << "total:" << total; + + m_ui->progressBar->setMaximum( total ); + m_ui->progressBar->setValue( page ); + + if ( page < total ) + loadHistory( ++page ); + else + finished = true; + } + else + finished = true; + } + catch( lastfm::ws::ParseError e ) + { + tDebug() << "XmlQuery error:" << e.what(); + finished = true; + } + + if ( finished ) + { + if ( m_ui->progressBar->value() != m_ui->progressBar->maximum() ) + m_ui->importHistory->setText( tr( "History Incomplete. Retry" ) ); + else + m_ui->importHistory->setText( tr( "Import Playback History" ) ); + + m_ui->importHistory->setEnabled( true ); + } +} + + void LastFmConfig::onLastFmFinished() { diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/accounts/lastfm/LastFmConfig.h index f6e0d72be..765f4a831 100644 --- a/src/accounts/lastfm/LastFmConfig.h +++ b/src/accounts/lastfm/LastFmConfig.h @@ -24,6 +24,7 @@ class Ui_LastFmConfig; namespace Tomahawk { + namespace Accounts { class LastFmAccount; @@ -39,11 +40,14 @@ public: bool scrobble() const; public slots: - void testLogin( bool ); + void testLogin(); void onLastFmFinished(); private slots: void enableButton(); + + void loadHistory( int page = 1 ); + void onHistoryLoaded(); private: LastFmAccount* m_account; @@ -51,6 +55,7 @@ private: }; } + } #endif // LASTFMCONFIG_H diff --git a/src/accounts/lastfm/LastFmConfig.ui b/src/accounts/lastfm/LastFmConfig.ui index 5cdf0e5e8..1a75ae970 100644 --- a/src/accounts/lastfm/LastFmConfig.ui +++ b/src/accounts/lastfm/LastFmConfig.ui @@ -7,7 +7,7 @@ 0 0 400 - 220 + 253 @@ -77,6 +77,20 @@ + + + + Import Playback History + + + + + + + 0 + + + diff --git a/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp b/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp index 81ee8fbd6..37e089940 100644 --- a/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp +++ b/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp @@ -37,31 +37,33 @@ using namespace Tomahawk; void DatabaseCommand_LogPlayback::postCommitHook() { + if ( !m_query.isNull() ) + return; + connect( this, SIGNAL( trackPlaying( Tomahawk::query_ptr, unsigned int ) ), source().data(), SLOT( onPlaybackStarted( Tomahawk::query_ptr, unsigned int ) ), Qt::QueuedConnection ); connect( this, SIGNAL( trackPlayed( Tomahawk::query_ptr ) ), source().data(), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection ); - Tomahawk::query_ptr q; - if ( !m_result.isNull() ) + if ( !m_result.isNull() && m_query.isNull() ) { - q = m_result->toQuery(); + m_query = m_result->toQuery(); } else { // do not auto resolve this track - q = Tomahawk::Query::get( m_artist, m_track, QString() ); + m_query = Tomahawk::Query::get( m_artist, m_track, QString() ); } - q->setPlayedBy( source(), m_playtime ); + m_query->setPlayedBy( source(), m_playtime ); if ( m_action == Finished ) { - emit trackPlayed( q ); + emit trackPlayed( m_query ); } // if the play time is more than 10 minutes in the past, ignore else if ( m_action == Started && QDateTime::fromTime_t( playtime() ).secsTo( QDateTime::currentDateTime() ) < STARTED_THRESHOLD ) { - emit trackPlaying( q, m_trackDuration ); + emit trackPlaying( m_query, m_trackDuration ); } if ( source()->isLocal() ) @@ -78,25 +80,36 @@ DatabaseCommand_LogPlayback::exec( DatabaseImpl* dbi ) if ( m_action != Finished ) return; - if ( m_secsPlayed < FINISHED_THRESHOLD ) + if ( m_secsPlayed < FINISHED_THRESHOLD && m_trackDuration > 0 ) + return; + if ( m_artist.isEmpty() || m_track.isEmpty() ) return; - TomahawkSqlQuery query = dbi->newquery(); - query.prepare( "INSERT INTO playback_log(source, track, playtime, secs_played) " - "VALUES (?, ?, ?, ?)" ); - QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id(); - qDebug() << "Logging playback of" << m_artist << "-" << m_track << "for source" << srcid; + TomahawkSqlQuery query = dbi->newquery(); + + if ( !m_query.isNull() ) + { + query.prepare( QString( "SELECT * FROM playback_log WHERE source %1 AND playtime = %2" ).arg( srcid.isNull() ? "IS NULL" : srcid.toString() ).arg( m_playtime ) ); + query.exec(); + if ( query.next() ) + { + tDebug() << "Ignoring dupe playback log for source" << srcid << "with timestamp" << m_playtime; + return; + } + } + +// tDebug() << "Logging playback of" << m_artist << "-" << m_track << "for source" << srcid << "- timestamp:" << m_playtime; + + query.prepare( "INSERT INTO playback_log(source, track, playtime, secs_played) VALUES (?, ?, ?, ?)" ); query.bindValue( 0, srcid ); - // If there's no artist, becuase it's a resolver result with bad metadata for example, don't save it - bool autoCreate = m_artist.isEmpty(); - int artid = dbi->artistId( m_artist, autoCreate ); + // If there's no artist, because it's a resolver result with bad metadata for example, don't save it + int artid = dbi->artistId( m_artist, true ); if( artid < 1 ) return; - autoCreate = true; // artistId overwrites autoCreate (reference) - int trkid = dbi->trackId( artid, m_track, autoCreate ); + int trkid = dbi->trackId( artid, m_track, true ); if( trkid < 1 ) return; diff --git a/src/libtomahawk/database/DatabaseCommand_LogPlayback.h b/src/libtomahawk/database/DatabaseCommand_LogPlayback.h index 384a07579..14912ca55 100644 --- a/src/libtomahawk/database/DatabaseCommand_LogPlayback.h +++ b/src/libtomahawk/database/DatabaseCommand_LogPlayback.h @@ -51,6 +51,17 @@ public: : DatabaseCommandLoggable( parent ), m_playtime( 0 ), m_secsPlayed( 0 ), m_trackDuration( 0 ) {} + explicit DatabaseCommand_LogPlayback( const Tomahawk::query_ptr& query, Action action, uint timeStamp, QObject* parent = 0 ) + : DatabaseCommandLoggable( parent ), m_query( query ), m_secsPlayed( 0 ), m_action( action ) + { + m_playtime = timeStamp; + m_trackDuration = 0; + setSource( SourceList::instance()->getLocal() ); + + setArtist( query->artist() ); + setTrack( query->track() ); + } + explicit DatabaseCommand_LogPlayback( const Tomahawk::result_ptr& result, Action action, unsigned int secsPlayed = 0, QObject* parent = 0 ) : DatabaseCommandLoggable( parent ), m_result( result ), m_secsPlayed( secsPlayed ), m_action( action ) { @@ -96,6 +107,7 @@ signals: private: Tomahawk::result_ptr m_result; + Tomahawk::query_ptr m_query; QString m_artist; QString m_track; From ac8703c9e78d4b127c9655a73b58c1d6a95aca98 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 11:38:12 +0200 Subject: [PATCH 009/433] * Robuster error / retry handling. --- src/accounts/lastfm/LastFmConfig.cpp | 29 +++++++++++++++++----------- src/accounts/lastfm/LastFmConfig.h | 4 +++- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index a0e5caa6b..5b98e76be 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -34,6 +34,7 @@ using namespace Tomahawk::Accounts; LastFmConfig::LastFmConfig( LastFmAccount* account ) : QWidget( 0 ) , m_account( account ) + , m_page( 1 ) { m_ui = new Ui_LastFmConfig; m_ui->setupUi( this ); @@ -105,9 +106,9 @@ LastFmConfig::enableButton() void -LastFmConfig::loadHistory( int page ) +LastFmConfig::loadHistory() { - if ( page == 1 ) + if ( m_page == 1 ) { m_ui->importHistory->setText( tr( "Importing History..." ) ); m_ui->importHistory->setEnabled( false ); @@ -115,7 +116,7 @@ LastFmConfig::loadHistory( int page ) m_ui->progressBar->show(); } - QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, page ); + QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, m_page ); connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) ); } @@ -123,6 +124,7 @@ LastFmConfig::loadHistory( int page ) void LastFmConfig::onHistoryLoaded() { + int total = 0; bool finished = false; QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); @@ -132,7 +134,7 @@ LastFmConfig::onHistoryLoaded() foreach ( lastfm::XmlQuery e, lfm.children( "track" ) ) { - tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt(); +// tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt(); Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false ); uint timeStamp = e["date"].attribute( "uts" ).toUInt(); @@ -145,14 +147,16 @@ LastFmConfig::onHistoryLoaded() lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first(); int page = stats.attribute( "page" ).toInt(); - int total = stats.attribute( "totalPages" ).toInt(); - tDebug() << "page:" << page << "total:" << total; + total = stats.attribute( "totalPages" ).toInt(); m_ui->progressBar->setMaximum( total ); m_ui->progressBar->setValue( page ); if ( page < total ) - loadHistory( ++page ); + { + m_page = page + 1; + loadHistory(); + } else finished = true; } @@ -167,12 +171,15 @@ LastFmConfig::onHistoryLoaded() if ( finished ) { - if ( m_ui->progressBar->value() != m_ui->progressBar->maximum() ) + if ( m_page != total ) + { m_ui->importHistory->setText( tr( "History Incomplete. Retry" ) ); + m_ui->importHistory->setEnabled( true ); + } else - m_ui->importHistory->setText( tr( "Import Playback History" ) ); - - m_ui->importHistory->setEnabled( true ); + { + m_ui->importHistory->setText( tr( "Playback History Imported" ) ); + } } } diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/accounts/lastfm/LastFmConfig.h index 765f4a831..f50416c22 100644 --- a/src/accounts/lastfm/LastFmConfig.h +++ b/src/accounts/lastfm/LastFmConfig.h @@ -46,12 +46,14 @@ public slots: private slots: void enableButton(); - void loadHistory( int page = 1 ); + void loadHistory(); void onHistoryLoaded(); private: LastFmAccount* m_account; Ui_LastFmConfig* m_ui; + + unsigned int m_page; }; } From 2558202a52bcbd65ab740fb31041aa97295f90ae Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 11:48:05 +0200 Subject: [PATCH 010/433] * Update the button status while the import is ongoing. --- src/accounts/lastfm/LastFmConfig.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index 5b98e76be..01c9421ab 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -108,13 +108,9 @@ LastFmConfig::enableButton() void LastFmConfig::loadHistory() { - if ( m_page == 1 ) - { - m_ui->importHistory->setText( tr( "Importing History..." ) ); - m_ui->importHistory->setEnabled( false ); - - m_ui->progressBar->show(); - } + m_ui->importHistory->setText( tr( "Importing History..." ) ); + m_ui->importHistory->setEnabled( false ); + m_ui->progressBar->show(); QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, m_page ); connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) ); From 5b2a5b76a4c27dd4f011813a6a54e3e6ac691408 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 12:01:03 +0200 Subject: [PATCH 011/433] * Show current import date. --- src/accounts/lastfm/LastFmConfig.cpp | 13 ++++++++++--- src/accounts/lastfm/LastFmConfig.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index 01c9421ab..170c993ed 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -35,6 +35,7 @@ LastFmConfig::LastFmConfig( LastFmAccount* account ) : QWidget( 0 ) , m_account( account ) , m_page( 1 ) + , m_lastTimeStamp( 0 ) { m_ui = new Ui_LastFmConfig; m_ui->setupUi( this ); @@ -108,7 +109,13 @@ LastFmConfig::enableButton() void LastFmConfig::loadHistory() { - m_ui->importHistory->setText( tr( "Importing History..." ) ); + if ( m_lastTimeStamp ) + { + m_ui->importHistory->setText( tr( "Importing %1", "e.g. Importing 2012/01/01" ).arg( QDateTime::fromTime_t( m_lastTimeStamp ).toString( "MMMM d yyyy" ) ) ); + } + else + m_ui->importHistory->setText( tr( "Importing History..." ) ); + m_ui->importHistory->setEnabled( false ); m_ui->progressBar->show(); @@ -132,9 +139,9 @@ LastFmConfig::onHistoryLoaded() { // tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt(); Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false ); - uint timeStamp = e["date"].attribute( "uts" ).toUInt(); + m_lastTimeStamp = e["date"].attribute( "uts" ).toUInt(); - DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, timeStamp ); + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, m_lastTimeStamp ); Database::instance()->enqueue( QSharedPointer(cmd) ); } diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/accounts/lastfm/LastFmConfig.h index f50416c22..cc6bfc8fb 100644 --- a/src/accounts/lastfm/LastFmConfig.h +++ b/src/accounts/lastfm/LastFmConfig.h @@ -54,6 +54,7 @@ private: Ui_LastFmConfig* m_ui; unsigned int m_page; + unsigned int m_lastTimeStamp; }; } From 2deb9bcdc1bf96a033510bfdd2aaafb8a6a64a88 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 12:11:27 +0200 Subject: [PATCH 012/433] * Wording: Resume instead of Retry. --- src/accounts/lastfm/LastFmConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index 170c993ed..9fd240abe 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -176,7 +176,7 @@ LastFmConfig::onHistoryLoaded() { if ( m_page != total ) { - m_ui->importHistory->setText( tr( "History Incomplete. Retry" ) ); + m_ui->importHistory->setText( tr( "History Incomplete. Resume" ) ); m_ui->importHistory->setEnabled( true ); } else From 413bddaf7d0d9573e39f8a871f2a70fe875eb501 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 22 May 2012 13:11:38 +0200 Subject: [PATCH 013/433] * Updated ChangeLog. --- ChangeLog | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index faa496d26..c0b0016c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,15 @@ +Version 0.5.0: + * Added "Stop playback after this track" context menu items. + * You can now import your entire Last.fm playback history into Tomahawk. + * Support for multimedia keys (Play, Pause, Next etc.) on Windows & Linux. + * When listening privately scrobbling to Last.fm is now disabled. + * Added a toolbar with page back / forward buttons and the global search. + * New grid view with direct playback controls. + * Added a track page showing a song's lyrics and other similar tracks. + * Separate Loved Tracks and Recently Played views per source. + Version 0.4.2: * Fix ZeroConf protocol showing IP addresses instead of host names. - Sometimes. Full fix coming later. * Updated translations for various languages. * Resuming playback restores correct volume settings. * Reduced CPU usage during playback. @@ -22,7 +31,7 @@ Version 0.4.0: * Fixed icons not appearing in resolvers list. * Fixed various UI glitches and stray error messages in stations. * Fixed bug where album page would resolve bottom-to-top. - * Fixed bug where Footnotes would not update when changing selected album in Album View. + * Fixed bug where Footnotes would not update when changing selected album. * Fixed dragging albums and artists from charts, album, and artist views. * Fixed bug where filter text would be one step behind filter value. * Fixed bug where resolvers would enable themselves after auto-updating. From 5766ea382b4d594d5baea0814c6524ab730f50a1 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 08:13:04 -0400 Subject: [PATCH 014/433] Fix heisenbug --- src/libtomahawk/accounts/AccountModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index d853b8c46..73550b688 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -95,8 +95,8 @@ AccountModel::loadData() if ( acct ) { m_accounts << new AccountModelNode( acct ); -#if ACCOUNTMODEL_DEBUG const int removed = allAccounts.removeAll( acct ); +#if ACCOUNTMODEL_DEBUG qDebug() << "Removed custom account from misc accounts list, found:" << removed; qDebug() << "All accounts after remove:"; foreach ( Account* acct, allAccounts ) From b308212214a06e338a91c2549cfbc2fdb20852be Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 08:34:51 -0400 Subject: [PATCH 015/433] Properly download+install binary payload on linux --- src/accounts/spotify/SpotifyAccount.cpp | 8 +++++-- src/libtomahawk/AtticaManager.cpp | 8 +++++-- src/libtomahawk/utils/TomahawkUtils.cpp | 31 +++++++++++++------------ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index c4f2ba289..a14fbbb5d 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -52,8 +52,12 @@ static QPixmap* s_icon = 0; static QString s_resolverId = "spotify-osx"; #elif defined(Q_OS_WIN) static QString s_resolverId = "spotify-win"; +#elif defined(Q_OS_LINUX) && defined(__GNUC__) && defined(__x86_64__) +static QString s_resolverId = "spotify-linux-x64"; +#elif defined(Q_OS_LINUX) +static QString s_resolverId = "spotify-linux-x86"; #else -static QString s_resolverId = "spotify-linux"; +static QString s_resolverId = "spotify-unknown"; #endif Account* @@ -171,7 +175,7 @@ SpotifyAccount::checkForResolver() const QDir path = QCoreApplication::applicationDirPath(); QFile file( path.absoluteFilePath( "spotify_tomahawkresolver" ) ); return file.exists(); -#else if defined(Q_OS_WIN) +#elif defined(Q_OS_WIN) QDir appDataDir = TomahawkUtils::appDataDir(); return appDataDir.exists( QString( "atticaresolvers/%1/spotify_tomahawkresolver.exe" ).arg( s_resolverId ) ); #endif diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index 3d89a7593..c53c2377b 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -345,7 +345,11 @@ AtticaManager::binaryResolversList( BaseJob* j ) platform = "osx"; #elif defined(Q_OS_WIN) platform = "win"; -#endif +#elif defined(Q_OS_LINUX) && defined(__GNUC__) && defined(__x86_64__) + platform = "linux-x64"; +#elif defined(Q_OS_LINUX) // Horrible assumption here... + platform = "linux-x86"; + #endif foreach ( const Content& c, binaryResolvers ) { @@ -533,7 +537,7 @@ AtticaManager::payloadFetched() else { TomahawkUtils::extractBinaryResolver( f.fileName(), new BinaryInstallerHelper( resolverId, reply->property( "createAccount" ).toBool(), this ) ); - // Don't emit success or failed yet, helpre will do that. + // Don't emit success or failed yet, helper will do that. return; } } diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 07471f42e..2db7ccb3b 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -848,17 +849,6 @@ unzipFileInFolder( const QString &zipFileName, const QDir &folder ) void extractBinaryResolver( const QString& zipFilename, QObject* receiver ) { -#ifndef Q_OS_MAC - Q_UNUSED( zipFilename ); - Q_UNUSED( receiver ); -#endif - -#if !defined(Q_OS_MAC) && !defined (Q_OS_WIN) - Q_ASSERT( false ); - qWarning() << "NO SUPPORT YET FOR LINUX BINARY RESOLVERS!"; - return; -#endif - #ifdef Q_OS_MAC // Platform-specific handling of resolver payload now. We know it's good // Unzip the file. @@ -884,7 +874,9 @@ extractBinaryResolver( const QString& zipFilename, QObject* receiver ) qDebug() << "OS X: Copying binary resolver from to:" << src << dest; copyWithAuthentication( src, dest, receiver ); -#elif defined(Q_OS_WIN) + + return; +#elif defined(Q_OS_WIN) || defined(Q_OS_LINUX) // We unzip directly to the target location, just like normal attica resolvers Q_ASSERT( receiver ); if ( !receiver ) @@ -897,19 +889,28 @@ extractBinaryResolver( const QString& zipFilename, QObject* receiver ) return; const QDir resolverPath( extractScriptPayload( zipFilename, resolverId ) ); +#endif + +#ifdef Q_OS_WIN const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); +#elif defined(Q_OS_LINUX) + const QStringList files = resolverPath.entryList( QStringList() << "*_tomahawkresolver", QDir::Files ); +#endif + qDebug() << "Found executables in unzipped binary resolver dir:" << files; Q_ASSERT( files.size() == 1 ); if ( files.size() < 1 ) return; const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); - QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG( QString, resolverToUse ) ); +#ifdef Q_OS_LINUX + QProcess p; + p.start( "chmod", QStringList() << "744" << resolverToUse, QIODevice::ReadOnly ); + p.waitForFinished( 6000 ); #endif - // No support for binary resolvers on linux! Shouldn't even have been allowed to see/install.. - Q_ASSERT( false ); + QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG( QString, resolverToUse ) ); } From e91d9e55f6065e75925524f5c67c61dfbdba1922 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 20 May 2012 17:11:53 -0400 Subject: [PATCH 016/433] Fix slow network causing multiple spotify accounts to show up --- src/accounts/spotify/SpotifyAccount.cpp | 16 ++++++++++++---- src/accounts/spotify/SpotifyAccount.h | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index a14fbbb5d..725d1f9e9 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -97,16 +97,24 @@ SpotifyAccount::init() setAccountFriendlyName( "Spotify" ); setAccountServiceName( "spotify" ); + AtticaManager::instance()->registerCustomAccount( s_resolverId, this ); + qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" ); + if ( !AtticaManager::instance()->resolversLoaded() ) { // If we're still waiting to load, wait for the attica resolvers to come down the pipe - connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( init() ), Qt::UniqueConnection ); - return; + connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( delayedInit() ), Qt::UniqueConnection ); } + else + { + delayedInit(); + } +} - qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" ); - AtticaManager::instance()->registerCustomAccount( s_resolverId, this ); +void +SpotifyAccount::delayedInit() +{ connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) ); diff --git a/src/accounts/spotify/SpotifyAccount.h b/src/accounts/spotify/SpotifyAccount.h index af05d0be6..69448b27b 100644 --- a/src/accounts/spotify/SpotifyAccount.h +++ b/src/accounts/spotify/SpotifyAccount.h @@ -118,10 +118,11 @@ private slots: void startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg ); void playlistCreated( const QString& msgType, const QVariantMap& msg ); - void init(); + void delayedInit(); void hookupAfterDeletion( bool autoEnable ); private: + void init(); bool checkForResolver(); void hookupResolver(); From bb62fd60471d426f6928755e18a8d3d20318efe7 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 10:34:08 -0400 Subject: [PATCH 017/433] Try harder to find an account --- src/libtomahawk/accounts/AccountModel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 73550b688..822acd6e7 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -729,6 +729,12 @@ AccountModel::indexForAtticaId( const QString& resolverId ) const { return index( i, 0, QModelIndex() ); } + else if ( m_accounts[ i ]->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( m_accounts[ i ]->customAccount ) ) + { + const CustomAtticaAccount* atticaAcct = qobject_cast< CustomAtticaAccount* >( m_accounts[ i ]->customAccount ); + if ( atticaAcct->atticaContent().id() == resolverId ) + return index( i, 0, QModelIndex() ); + } } return QModelIndex(); From e4bd229ef0c6b89d37206a3a5ce39744887350e9 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 10:38:54 -0400 Subject: [PATCH 018/433] OSX fix --- src/libtomahawk/utils/TomahawkUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 2db7ccb3b..16d8e2a70 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -889,7 +889,6 @@ extractBinaryResolver( const QString& zipFilename, QObject* receiver ) return; const QDir resolverPath( extractScriptPayload( zipFilename, resolverId ) ); -#endif #ifdef Q_OS_WIN const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); @@ -911,6 +910,8 @@ extractBinaryResolver( const QString& zipFilename, QObject* receiver ) #endif QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG( QString, resolverToUse ) ); + +#endif } From b66e191078bc2236b791257d275bac0b1f6d190d Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Tue, 22 May 2012 22:16:39 +0000 Subject: [PATCH 019/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_bg.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_ca.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_de.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_en.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_es.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_fr.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_ja.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_pl.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_pt_BR.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_ru.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_sv.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_tr.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_zh_CN.ts | 88 ++++++++++++++++++++++++++++-------------- lang/tomahawk_zh_TW.ts | 88 ++++++++++++++++++++++++++++-------------- 15 files changed, 885 insertions(+), 435 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 7ff72da0d..c794d760a 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login اختبار الدخول + + + Import Playback History + + LastfmContext @@ -888,67 +893,67 @@ connect and stream from you? QObject - + %n year(s) ago منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago منذ %1 دقائق - + %1 minutes %1 دقائق - + just now الآن @@ -1677,23 +1682,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login اختبار الدخول - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed فشلت - + Success نجاح - + Could not contact server لم أستطيع الإتصال بالخادم @@ -1701,12 +1732,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2738,39 +2769,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window إخفي نافذة توماهوك - + Show Tomahawk Window أظهر نافذة توماهوك - + Currently not playing. - + Play - + Pause - + &Continue Playback after current Track diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index d44c74a84..e4c0451f2 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -558,6 +558,11 @@ Tomahaw създаде доклад относно това и изпращай Test Login Пробна връзка + + + Import Playback History + + LastfmContext @@ -890,67 +895,67 @@ Tomahaw създаде доклад относно това и изпращай QObject - + %n year(s) ago преди %n годинапреди %n години - + %n year(s) %n година%n години - + %n month(s) ago преди %n месецпреди %n месеца - + %n month(s) %n месец%n месеца - + %n week(s) ago преди %n седмицапреди %n седмици - + %n week(s) %n седмица%n седмици - + %n day(s) ago преди %n денпреди %n дена - + %n day(s) %n ден%n дена - + %n hour(s) ago преди %n часпреди %n часа - + %n hour(s) %n час %n часа - + %1 minutes ago преди %1 минути - + %1 minutes %1 минути - + just now току-що @@ -1684,23 +1689,49 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Тествай връзката - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Неуспешно - + Success Ура! - + Could not contact server Не мога да се свържа със сървъра @@ -1708,12 +1739,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -2752,39 +2783,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track &Спри възпроизвеждането след текущата песен - - + + Hide Tomahawk Window Скрий главният прозорец - + Show Tomahawk Window Покажи главният прозорец - + Currently not playing. В момента не се изпълнява нищо - + Play Изпълни - + Pause Пауза - + &Continue Playback after current Track &Продължи възпроизвеждането след текущата песен diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 62a19456b..ce7802730 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login Comprova l'autenticació + + + Import Playback History + + LastfmContext @@ -887,67 +892,67 @@ connect and stream from you? QObject - + %n year(s) ago fa %n anyfa %n anys - + %n year(s) %n any%n anys - + %n month(s) ago fa %n mesfa %n mesos - + %n month(s) %n mes%n mesos - + %n week(s) ago fa %n setmanafa %n setmanes - + %n week(s) %n setmana%n setmanes - + %n day(s) ago fa %n diafa %n dies - + %n day(s) %n dia%n dies - + %n hour(s) ago fa %n horafa %n hores - + %n hour(s) %n hora%n hores - + %1 minutes ago fa %1 minut - + %1 minutes %1 minuts - + just now ara mateix @@ -1679,23 +1684,49 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Comprova l'inici de sessió - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Error - + Success Èxit - + Could not contact server No s'ha pogut contactar amb el servidor @@ -1703,12 +1734,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -2746,39 +2777,38 @@ introduïu el PIN aquí: TomahawkTrayIcon - - + &Stop Playback after current Track &Atura la Reproducció després d'aquesta Cançó - - + + Hide Tomahawk Window Amaga la finestra de Tomahawk - + Show Tomahawk Window Mostra la finestra de Tomahawk - + Currently not playing. No s'està reproduint res. - + Play Reprodueix - + Pause Pausa - + &Continue Playback after current Track &Continua la reproducció després d'aquesta Cançó diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index d4c523de8..ae66ce38f 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login Login testen + + + Import Playback History + + LastfmContext @@ -887,67 +892,67 @@ connect and stream from you? QObject - + %n year(s) ago vor %n Jahrvor %n Jahren - + %n year(s) %n Jahr%n Jahre - + %n month(s) ago vor %n Monatvor %n Monaten - + %n month(s) %n Monat%n Monate - + %n week(s) ago vor %n Wochevor %n Wochen - + %n week(s) %n Woche%n Wochen - + %n day(s) ago vor %n Tagvor %n Tagen - + %n day(s) %n Tag%n Tage - + %n hour(s) ago vor %n Stundevor %n Stunden - + %n hour(s) %n Stunde%n Stunden - + %1 minutes ago vor %1 Minute - + %1 minutes %1 Minuten - + just now gerade eben @@ -1676,23 +1681,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Login testen - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Fehlgeschlagen - + Success Erfolgreich - + Could not contact server Konnte den Server nicht erreichen! @@ -1700,12 +1731,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + Stop syncing with Spotify Synchronisation beenden @@ -2741,39 +2772,38 @@ Tomahawk auf Twitter's Website authentifiziert hast: TomahawkTrayIcon - - + &Stop Playback after current Track Wiedergabe nach diesem Lied &stoppen - - + + Hide Tomahawk Window Tomahawk verbergen - + Show Tomahawk Window Tomahawk anzeigen - + Currently not playing. Derzeit wird nichts gespielt. - + Play Abspielen - + Pause Pause - + &Continue Playback after current Track Wiedergabe nach diesem Lied &fortsetzen diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 3d24dedbb..6fec66a33 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -555,6 +555,11 @@ connect and stream from you? Test Login Test Login + + + Import Playback History + Import Playback History + LastfmContext @@ -888,67 +893,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutes ago - + %1 minutes %1 minutes - + just now just now @@ -1680,23 +1685,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + Testing... + + + Test Login Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + Importing %1 + + + + Importing History... + Importing History... + + + + History Incomplete. Resume + History Incomplete. Resume + + + + Playback History Imported + Playback History Imported + + + + Failed Failed - + Success Success - + Could not contact server Could not contact server @@ -1704,12 +1735,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + Stop syncing with Spotify Stop syncing with Spotify @@ -2747,39 +2778,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track &Stop Playback after current Track - - + + Hide Tomahawk Window Hide Tomahawk Window - + Show Tomahawk Window Show Tomahawk Window - + Currently not playing. Currently not playing. - + Play Play - + Pause Pause - + &Continue Playback after current Track &Continue Playback after current Track diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 73a09ae35..6a9d70506 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login Probar conexión + + + Import Playback History + + LastfmContext @@ -886,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago hace %n añohace%n años - + %n year(s) %n año%n años - + %n month(s) ago hace %n meshace %n meses - + %n month(s) %n mes%n meses - + %n week(s) ago hace %n semanahace %n semanas - + %n week(s) %n semana%n semanas - + %n day(s) ago hace %n díahace %n días - + %n day(s) %n día%n días - + %n hour(s) ago hace %n horahace %n horas - + %n hour(s) %n hora%n horas - + %1 minutes ago hace %1 minutos - + %1 minutes %1 minutos - + just now justo ahora @@ -1678,23 +1683,49 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Comprobar Inicio de Sesión - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Fallo - + Success Éxito - + Could not contact server No se pudo contactar el servidor @@ -1702,12 +1733,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -2745,39 +2776,38 @@ introduzca su número PIN aquí: TomahawkTrayIcon - - + &Stop Playback after current Track &Para la Reproducción después de este Tema - - + + Hide Tomahawk Window Ocultar ventana de Tomahawk - + Show Tomahawk Window Mostrar ventana de Tomahawk - + Currently not playing. Ninguna pista en reproducción. - + Play Reproducir - + Pause Pausar - + &Continue Playback after current Track &Continuar la Reproducción después de este Tema diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 4a555f1fe..33b99d3d3 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -555,6 +555,11 @@ se connecter et streamer depuis chez vous ? Test Login Login test + + + Import Playback History + + LastfmContext @@ -888,67 +893,67 @@ se connecter et streamer depuis chez vous ? QObject - + %n year(s) ago il y a %n anil y a %n ans - + %n year(s) %n an%n ans - + %n month(s) ago il y a %n moisil y a %n mois - + %n month(s) %n mois%n mois - + %n week(s) ago il y a %n semaineil y a %n semaines - + %n week(s) %n semaine%n semaines - + %n day(s) ago il y a %n jouril y a %n jours - + %n day(s) %n jour%n jours - + %n hour(s) ago il y a %n heureil y a %n heures - + %n hour(s) %n heure%n heures - + %1 minutes ago il y a %1 minutes - + %1 minutes %1 minutes - + just now à l'instant @@ -1680,23 +1685,49 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login Test de connexion - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Échec - + Success Succès - + Could not contact server Impossible de contacter le serveur @@ -1704,12 +1735,12 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -2747,39 +2778,38 @@ saisissez le numéro PIN ici : TomahawkTrayIcon - - + &Stop Playback after current Track &Stopper la lecture après cette piste - - + + Hide Tomahawk Window Masquer la fenêtre Tomahawk - + Show Tomahawk Window Afficher la fenêtre Tomahawk - + Currently not playing. Pas de lecture en cours - + Play Lecture - + Pause Pause - + &Continue Playback after current Track &Continuer la lecture après cette piste diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 49db53065..fe4bc11f5 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login + + + Import Playback History + + LastfmContext @@ -886,69 +891,69 @@ connect and stream from you? QObject - + %n year(s) ago one: %n年前 other: %n年前 - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1分前 - + %1 minutes %1分 - + just now 只今 @@ -1677,23 +1682,49 @@ other: %n年前 Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1701,12 +1732,12 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2736,39 +2767,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Tomahawkのウインドウを隠す - + Show Tomahawk Window Tomahawkのウインドウを表示 - + Currently not playing. - + Play 再生 - + Pause 一時停止 - + &Continue Playback after current Track diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 5d1a6c891..f1b18344c 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login Test logowania + + + Import Playback History + + LastfmContext @@ -886,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago %n rok temu%n lata temu%n lat temu - + %n year(s) %n rok%n lata%n lat - + %n month(s) ago %n miesiąc temu%n miesiące temu%n miesięcy temu - + %n month(s) %n miesiąc%n miesiące%n miesięcy - + %n week(s) ago %n tydzień temu%n tygodnie temu%n tygodni temu - + %n week(s) %n tydzień%n tygodnie%n tygodni - + %n day(s) ago %n dzień temu%n dni temu%n dni temu - + %n day(s) %n dzień%n dni%n dni - + %n hour(s) ago %n godzinę temu%n godziny temu%n godzin temu - + %n hour(s) %n godzinę%n godziny%n godzin - + %1 minutes ago %1 minut temu - + %1 minutes %1 minut - + just now przed chwilą @@ -1679,23 +1684,49 @@ indywidualnego profilu gustu. Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1703,12 +1734,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2741,39 +2772,38 @@ wprowadź pokazany numer PIN tutaj: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Ukryj Okno Tomahawka - + Show Tomahawk Window Pokaż Okno Tomahawka - + Currently not playing. Aktualnie nie odtwarza. - + Play Odtwarzaj - + Pause Pauza - + &Continue Playback after current Track diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 3a27083af..ac3fef10e 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login + + + Import Playback History + + LastfmContext @@ -886,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutos atrás - + %1 minutes %1 minutos - + just now agora @@ -1678,23 +1683,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Falhou - + Success Sucesso - + Could not contact server @@ -1702,12 +1733,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2740,39 +2771,38 @@ colocar o número PIN mostrado aqui: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Esconder janela do Tomahawk - + Show Tomahawk Window Mostrar janela do Tomahawk - + Currently not playing. Não reproduzindo nada. - + Play Reporduzir - + Pause Pausar - + &Continue Playback after current Track diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 38aa55036..45bd49a7e 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -555,6 +555,11 @@ connect and stream from you? Test Login Проверить + + + Import Playback History + + LastfmContext @@ -888,67 +893,67 @@ connect and stream from you? QObject - + %n year(s) ago %n год назад%n года назад%n лет назад - + %n year(s) %n год%n года%n лет - + %n month(s) ago %n месяц назад%n месяца назад%n месяцей назад - + %n month(s) %n месяц%n месяца%n месяцей - + %n week(s) ago %n неделю назад%n недели назад%n недель назад - + %n week(s) %n неделю%n недели%n недель - + %n day(s) ago %n день назад%n дня назад%n дней назад - + %n day(s) %n день%n дня%n дней - + %n hour(s) ago %n час назад%n часа назад%n часов назад - + %n hour(s) %n час%n часа%n часов - + %1 minutes ago %1 минут(ы) назад - + %1 minutes %1 минут(ы) - + just now только что @@ -1677,23 +1682,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed Неудача - + Success Успех - + Could not contact server Не удается связаться с сервером @@ -1701,12 +1732,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -2741,39 +2772,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track &Остановить после текущего трека - - + + Hide Tomahawk Window Спрятать окно Tomahawk - + Show Tomahawk Window Показать окно Tomahawk - + Currently not playing. Не воспроизводится. - + Play Играть - + Pause Пауза - + &Continue Playback after current Track &Продолжить воспроизведение после текущего трека diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 22b2fa6b9..0aeb744fb 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login Testinloggning + + + Import Playback History + + LastfmContext @@ -887,67 +892,67 @@ connect and stream from you? QObject - + %n year(s) ago %n år sedan%n år sedan - + %n year(s) %n år sedan%n år sedan - + %n month(s) ago %n månad sedan%n månader sedan - + %n month(s) %n månad%n månader - + %n week(s) ago %n vecka sedan%n veckor sedan - + %n week(s) %n vecka%n veckor - + %n day(s) ago %n dag sedan%n dagar sedan - + %n day(s) %n dag%n dagar - + %n hour(s) ago %n timme sedan%n timmar sedan - + %n hour(s) %n timme%n timmar - + %1 minutes ago %1 minuter sedan - + %1 minutes %1 minuter - + just now precis nyss @@ -1676,23 +1681,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1700,12 +1731,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2735,39 +2766,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window Dölj Tomahawk-fönstret - + Show Tomahawk Window Visa Tomahawk-fönstret - + Currently not playing. Spelar ingenting för närvarande. - + Play Spela upp - + Pause Paus - + &Continue Playback after current Track diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 3c93fbebe..cc73d23c4 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login Bilgileri Test Et + + + Import Playback History + + LastfmContext @@ -886,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -1675,23 +1680,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1699,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2734,39 +2765,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + &Continue Playback after current Track diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index b32a570aa..7bf37c6e5 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login 测试登录 + + + Import Playback History + + LastfmContext @@ -886,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -1675,23 +1680,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed - + Success - + Could not contact server @@ -1699,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2734,39 +2765,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + &Continue Playback after current Track diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 54e1a0e02..a5e79d8fe 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -554,6 +554,11 @@ connect and stream from you? Test Login 測試登錄 + + + Import Playback History + + LastfmContext @@ -886,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1 分鐘前 - + %1 minutes %1 分鐘 - + just now 剛才 @@ -1675,23 +1680,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + + Testing... + + + + Test Login - - + + Importing %1 + e.g. Importing 2012/01/01 + + + + + Importing History... + + + + + History Incomplete. Resume + + + + + Playback History Imported + + + + + Failed 失敗 - + Success 成功 - + Could not contact server 無法聯繫服務器 @@ -1699,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2734,39 +2765,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. 目前沒有播放。 - + Play 播放 - + Pause 暫停 - + &Continue Playback after current Track From 982945107e68924fc7c31c35f4bf9ae20cffe3ca Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 09:08:27 -0400 Subject: [PATCH 020/433] Handle linux in checkForResolver --- src/accounts/spotify/SpotifyAccount.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index 725d1f9e9..5805bcb00 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -186,6 +186,9 @@ SpotifyAccount::checkForResolver() #elif defined(Q_OS_WIN) QDir appDataDir = TomahawkUtils::appDataDir(); return appDataDir.exists( QString( "atticaresolvers/%1/spotify_tomahawkresolver.exe" ).arg( s_resolverId ) ); +#elif defined(Q_OS_LINUX) + QDir appDataDir = TomahawkUtils::appDataDir(); + return appDataDir.exists( QString( "atticaresolvers/%1/spotify_tomahawkresolver" ).arg( s_resolverId ) ); #endif return false; From a538553d17a1c0a828ea8fde96a86748ceb8a42f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 10:39:31 -0400 Subject: [PATCH 021/433] Do binary payload management in background --- src/libtomahawk/AtticaManager.cpp | 20 ++- .../utils/BinaryInstallerHelper.cpp | 12 +- src/libtomahawk/utils/BinaryInstallerHelper.h | 6 +- src/libtomahawk/utils/TomahawkUtils.cpp | 160 +++++++++++------- 4 files changed, 123 insertions(+), 75 deletions(-) diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index c53c2377b..bd604b37a 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -513,14 +513,14 @@ AtticaManager::payloadFetched() // we got a zip file, save it to a temporary file, then unzip it to our destination data dir if ( reply->error() == QNetworkReply::NoError ) { - QTemporaryFile f( QDir::tempPath() + QDir::separator() + "tomahawkattica_XXXXXX.zip" ); - if ( !f.open() ) + QTemporaryFile* f = new QTemporaryFile( QDir::tempPath() + QDir::separator() + "tomahawkattica_XXXXXX.zip" ); + if ( !f->open() ) { - tLog() << "Failed to write zip file to temp file:" << f.fileName(); + tLog() << "Failed to write zip file to temp file:" << f->fileName(); return; } - f.write( reply->readAll() ); - f.close(); + f->write( reply->readAll() ); + f->close(); if ( m_resolverStates[ resolverId ].binary ) { @@ -530,20 +530,20 @@ AtticaManager::payloadFetched() Q_ASSERT( !signature.isEmpty() ); if ( signature.isEmpty() ) return; - if ( !TomahawkUtils::verifyFile( f.fileName(), signature ) ) + if ( !TomahawkUtils::verifyFile( f->fileName(), signature ) ) { - qWarning() << "FILE SIGNATURE FAILED FOR BINARY RESOLVER! WARNING! :" << f.fileName() << signature; + qWarning() << "FILE SIGNATURE FAILED FOR BINARY RESOLVER! WARNING! :" << f->fileName() << signature; } else { - TomahawkUtils::extractBinaryResolver( f.fileName(), new BinaryInstallerHelper( resolverId, reply->property( "createAccount" ).toBool(), this ) ); + TomahawkUtils::extractBinaryResolver( f->fileName(), new BinaryInstallerHelper( f, resolverId, reply->property( "createAccount" ).toBool(), this ) ); // Don't emit success or failed yet, helper will do that. return; } } else { - QDir dir( TomahawkUtils::extractScriptPayload( f.fileName(), resolverId ) ); + QDir dir( TomahawkUtils::extractScriptPayload( f->fileName(), resolverId ) ); QString resolverPath = dir.absoluteFilePath( m_resolverStates[ resolverId ].scriptPath ); if ( !resolverPath.isEmpty() ) @@ -562,6 +562,8 @@ AtticaManager::payloadFetched() installedSuccessfully = true; } } + + delete f; } else { diff --git a/src/libtomahawk/utils/BinaryInstallerHelper.cpp b/src/libtomahawk/utils/BinaryInstallerHelper.cpp index e13cb9321..d061053ca 100644 --- a/src/libtomahawk/utils/BinaryInstallerHelper.cpp +++ b/src/libtomahawk/utils/BinaryInstallerHelper.cpp @@ -20,13 +20,16 @@ #include "accounts/AccountManager.h" #include "TomahawkSettingsGui.h" +#include -BinaryInstallerHelper::BinaryInstallerHelper( const QString& resolverId, bool createAccount, AtticaManager* manager ) +BinaryInstallerHelper::BinaryInstallerHelper( QTemporaryFile* tempFile, const QString& resolverId, bool createAccount, AtticaManager* manager ) : QObject( manager ) + , m_tempFile( tempFile ) , m_resolverId( resolverId ) , m_createAccount( createAccount ) , m_manager( QWeakPointer< AtticaManager >( manager ) ) { + Q_ASSERT( m_tempFile ); Q_ASSERT( !m_resolverId.isEmpty() ); Q_ASSERT( !m_manager.isNull() ); @@ -34,6 +37,13 @@ BinaryInstallerHelper::BinaryInstallerHelper( const QString& resolverId, bool cr } +BinaryInstallerHelper::~BinaryInstallerHelper() +{ + Q_ASSERT( m_tempFile ); + delete m_tempFile; +} + + void BinaryInstallerHelper::installSucceeded( const QString& path ) { diff --git a/src/libtomahawk/utils/BinaryInstallerHelper.h b/src/libtomahawk/utils/BinaryInstallerHelper.h index 511584581..33fbba7ce 100644 --- a/src/libtomahawk/utils/BinaryInstallerHelper.h +++ b/src/libtomahawk/utils/BinaryInstallerHelper.h @@ -22,19 +22,21 @@ #include +class QTemporaryFile; class BinaryInstallerHelper : public QObject { Q_OBJECT public: - explicit BinaryInstallerHelper( const QString& resolverId, bool createAccount, AtticaManager* manager ); + explicit BinaryInstallerHelper( QTemporaryFile* tempFile, const QString& resolverId, bool createAccount, AtticaManager* manager ); - virtual ~BinaryInstallerHelper() {} + virtual ~BinaryInstallerHelper(); public slots: void installSucceeded( const QString& path ); void installFailed(); private: + QTemporaryFile* m_tempFile; QString m_resolverId; bool m_createAccount; QWeakPointer m_manager; diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 16d8e2a70..6560ebc04 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -846,73 +846,107 @@ unzipFileInFolder( const QString &zipFileName, const QDir &folder ) } +class ScopedDeleter +{ +public: + ScopedDeleter( QObject* o ) : m_o( 0 ) {} + ~ScopedDeleter() { m_o->deleteLater(); } + +private: + QObject* m_o; +}; + + +class BinaryExtractWorker : public QThread +{ + Q_OBJECT +public: + BinaryExtractWorker( const QString& zipFilename, QObject* receiver ) : m_zipFileName( zipFilename ), m_receiver( receiver ) {} + virtual ~BinaryExtractWorker() {} + +protected: + virtual void run() + { + ScopedDeleter deleter( this ); + +#ifdef Q_OS_MAC + // Platform-specific handling of resolver payload now. We know it's good + // Unzip the file. + QFileInfo info( m_zipFileName ); + QDir tmpDir = QDir::tempPath(); + if ( !tmpDir.mkdir( info.baseName() ) ) + { + qWarning() << "Failed to create temporary directory to unzip in:" << tmpDir.absolutePath(); + return; + } + tmpDir.cd( info.baseName() ); + TomahawkUtils::unzipFileInFolder( info.absoluteFilePath(), tmpDir ); + + // On OSX it just contains 1 file, the resolver executable itself. For now. We just copy it to + // the Tomahawk.app/Contents/MacOS/ folder alongside the Tomahawk executable. + const QString dest = QCoreApplication::applicationDirPath(); + // Find the filename + const QDir toList( tmpDir.absolutePath() ); + const QStringList files = toList.entryList( QStringList(), QDir::Files ); + Q_ASSERT( files.size() == 1 ); + + const QString src = toList.absoluteFilePath( files.first() ); + qDebug() << "OS X: Copying binary resolver from to:" << src << dest; + + copyWithAuthentication( src, dest, m_receiver ); + + return; +#elif defined(Q_OS_WIN) || defined(Q_OS_LINUX) + // We unzip directly to the target location, just like normal attica resolvers + Q_ASSERT( m_receiver ); + if ( !m_receiver ) + return; + + const QString resolverId = m_receiver->property( "resolverid" ).toString(); + + Q_ASSERT( !resolverId.isEmpty() ); + if ( resolverId.isEmpty() ) + return; + + + const QDir resolverPath( extractScriptPayload( m_zipFileName, resolverId ) ); + +#ifdef Q_OS_WIN + const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); +#elif defined(Q_OS_LINUX) + const QStringList files = resolverPath.entryList( QStringList() << "*_tomahawkresolver", QDir::Files ); +#endif + + qDebug() << "Found executables in unzipped binary resolver dir:" << files; + Q_ASSERT( files.size() == 1 ); + if ( files.size() < 1 ) + return; + + const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); + +#ifdef Q_OS_LINUX + QProcess p; + p.start( "chmod", QStringList() << "744" << resolverToUse, QIODevice::ReadOnly ); + p.waitForFinished(); +#endif + + QMetaObject::invokeMethod( m_receiver, "installSucceeded", Qt::QueuedConnection, Q_ARG( QString, resolverToUse ) ); + +#endif + } +private: + QString m_zipFileName; + QObject* m_receiver; +}; + void extractBinaryResolver( const QString& zipFilename, QObject* receiver ) { -#ifdef Q_OS_MAC - // Platform-specific handling of resolver payload now. We know it's good - // Unzip the file. - QFileInfo info( zipFilename ); - QDir tmpDir = QDir::tempPath(); - if ( !tmpDir.mkdir( info.baseName() ) ) - { - qWarning() << "Failed to create temporary directory to unzip in:" << tmpDir.absolutePath(); - return; - } - tmpDir.cd( info.baseName() ); - TomahawkUtils::unzipFileInFolder( info.absoluteFilePath(), tmpDir ); - - // On OSX it just contains 1 file, the resolver executable itself. For now. We just copy it to - // the Tomahawk.app/Contents/MacOS/ folder alongside the Tomahawk executable. - const QString dest = QCoreApplication::applicationDirPath(); - // Find the filename - const QDir toList( tmpDir.absolutePath() ); - const QStringList files = toList.entryList( QStringList(), QDir::Files ); - Q_ASSERT( files.size() == 1 ); - - const QString src = toList.absoluteFilePath( files.first() ); - qDebug() << "OS X: Copying binary resolver from to:" << src << dest; - - copyWithAuthentication( src, dest, receiver ); - - return; -#elif defined(Q_OS_WIN) || defined(Q_OS_LINUX) - // We unzip directly to the target location, just like normal attica resolvers - Q_ASSERT( receiver ); - if ( !receiver ) - return; - - const QString resolverId = receiver->property( "resolverid" ).toString(); - - Q_ASSERT( !resolverId.isEmpty() ); - if ( resolverId.isEmpty() ) - return; - - const QDir resolverPath( extractScriptPayload( zipFilename, resolverId ) ); - -#ifdef Q_OS_WIN - const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); -#elif defined(Q_OS_LINUX) - const QStringList files = resolverPath.entryList( QStringList() << "*_tomahawkresolver", QDir::Files ); -#endif - - qDebug() << "Found executables in unzipped binary resolver dir:" << files; - Q_ASSERT( files.size() == 1 ); - if ( files.size() < 1 ) - return; - - const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); - -#ifdef Q_OS_LINUX - QProcess p; - p.start( "chmod", QStringList() << "744" << resolverToUse, QIODevice::ReadOnly ); - p.waitForFinished( 6000 ); -#endif - - QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG( QString, resolverToUse ) ); - -#endif + BinaryExtractWorker* worker = new BinaryExtractWorker( zipFilename, receiver ); + worker->start( QThread::LowPriority ); } } // ns + +#include "TomahawkUtils.moc" From af50be9ef8712a4b27d8ec5e821278d59f5caeea Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 10:55:07 -0400 Subject: [PATCH 022/433] Don't assert on a potentially valid condition --- src/AccountDelegate.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AccountDelegate.cpp b/src/AccountDelegate.cpp index 49eca49d7..1d7a23c01 100644 --- a/src/AccountDelegate.cpp +++ b/src/AccountDelegate.cpp @@ -725,7 +725,6 @@ void AccountDelegate::doneInstalling ( const QPersistentModelIndex& idx ) { qDebug() << "STOP INSTALLING:" << idx.data( Qt::DisplayRole ).toString(); - Q_ASSERT( m_loadingSpinners.contains( idx ) ); if ( !m_loadingSpinners.contains( idx ) ) return; From 92ec403f7c3cd96f6ad832547facfd933172712b Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 22 May 2012 22:03:18 -0400 Subject: [PATCH 023/433] Fixes for spotify and lastfm custom accounts, and fix some misc older bugs --- src/libtomahawk/AtticaManager.cpp | 28 ++++++- src/libtomahawk/AtticaManager.h | 9 +++ src/libtomahawk/accounts/AccountModel.cpp | 52 ++++++++---- src/libtomahawk/accounts/AccountModelNode.h | 3 - src/libtomahawk/accounts/ResolverAccount.cpp | 83 ++++++++++++++------ src/libtomahawk/accounts/ResolverAccount.h | 8 ++ 6 files changed, 140 insertions(+), 43 deletions(-) diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index bd604b37a..c6f2d95f4 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -438,7 +438,20 @@ AtticaManager::syncServerData() void -AtticaManager::installResolver( const Content& resolver, bool autoCreateAccount ) +AtticaManager::installResolver( const Content& resolver, bool autoCreate ) +{ + doInstallResolver( resolver, autoCreate, 0 ); +} + + +void +AtticaManager::installResolverWithHandler( const Content& resolver, Tomahawk::Accounts::AtticaResolverAccount* handler ) +{ + doInstallResolver( resolver, false, handler ); +} + + +void AtticaManager::doInstallResolver( const Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler ) { Q_ASSERT( !resolver.id().isNull() ); @@ -454,7 +467,8 @@ AtticaManager::installResolver( const Content& resolver, bool autoCreateAccount ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() ); connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) ); job->setProperty( "resolverId", resolver.id() ); - job->setProperty( "createAccount", autoCreateAccount ); + job->setProperty( "createAccount", autoCreate ); + job->setProperty( "handler", QVariant::fromValue< QObject* >( handler ) ); job->setProperty( "binarySignature", resolver.attribute("signature")); job->start(); @@ -492,6 +506,7 @@ AtticaManager::resolverDownloadFinished ( BaseJob* j ) connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) ); reply->setProperty( "resolverId", job->property( "resolverId" ) ); reply->setProperty( "createAccount", job->property( "createAccount" ) ); + reply->setProperty( "handler", job->property( "handler" ) ); reply->setProperty( "binarySignature", job->property( "binarySignature" ) ); } else @@ -551,7 +566,14 @@ AtticaManager::payloadFetched() // update with absolute, not relative, path m_resolverStates[ resolverId ].scriptPath = resolverPath; - if ( reply->property( "createAccount" ).toBool() ) + Tomahawk::Accounts::AtticaResolverAccount* handlerAccount = qobject_cast< Tomahawk::Accounts::AtticaResolverAccount* >( reply->property( "handler" ).value< QObject* >() ); + const bool createAccount = reply->property( "createAccount" ).toBool(); + if ( handlerAccount ) + { + handlerAccount->setPath( resolverPath ); + Tomahawk::Accounts::AccountManager::instance()->enableAccount( handlerAccount ); + } + else if ( createAccount ) { // Do the install / add to tomahawk Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, "resolveraccount", true ); diff --git a/src/libtomahawk/AtticaManager.h b/src/libtomahawk/AtticaManager.h index 079672529..b6b206069 100644 --- a/src/libtomahawk/AtticaManager.h +++ b/src/libtomahawk/AtticaManager.h @@ -32,6 +32,12 @@ #include #include +namespace Tomahawk { +namespace Accounts { +class AtticaResolverAccount; +} +} + class BinaryInstallerHelper; class DLLEXPORT AtticaManager : public QObject @@ -105,6 +111,8 @@ public: public slots: void installResolver( const Attica::Content& resolver, bool autoCreateAccount = true ); + void installResolverWithHandler( const Attica::Content& resolver, Tomahawk::Accounts::AtticaResolverAccount* handler ); + void upgradeResolver( const Attica::Content& resolver ); signals: @@ -133,6 +141,7 @@ private slots: private: QString extractPayload( const QString& filename, const QString& resolverId ) const; void doResolverRemove( const QString& id ) const; + void doInstallResolver( const Attica::Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler ); Attica::ProviderManager m_manager; diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 822acd6e7..9b1a6809e 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -109,10 +109,14 @@ AccountModel::loadData() foreach ( Account* acct, AccountManager::instance()->accounts( Accounts::ResolverType ) ) { -// qDebug() << "Found ResolverAccount" << acct->accountFriendlyName(); +#if ACCOUNTMODEL_DEBUG + qDebug() << "Found ResolverAccount" << acct->accountFriendlyName(); +#endif if ( AtticaResolverAccount* resolver = qobject_cast< AtticaResolverAccount* >( acct ) ) { -// qDebug() << "Which is an attica resolver with id:" << resolver->atticaId(); +#if ACCOUNTMODEL_DEBUG + qDebug() << "Which is an attica resolver with id:" << resolver->atticaId(); +#endif if ( resolver->atticaId() == content.id() ) { allAccounts.removeAll( acct ); @@ -345,12 +349,15 @@ AccountModel::data( const QModelIndex& index, int role ) const Q_ASSERT( node->customAccount ); Q_ASSERT( node->factory ); - Account* account = node->customAccount; - // This is sort of ugly. CustomAccounts are pure Account*, but we know that + Attica::Content content = node->atticaContent; + // This is ugly. CustomAccounts are pure Account*, but we know that // some might also be linked to attica resolvers (not always). If that is the case // they have a Attica::Content set on the node, so we use that to display some // extra metadata and rating - const bool hasAttica = !node->atticaContent.id().isEmpty(); + Account* account = node->customAccount; + if ( node->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( account ) ) + content = qobject_cast< CustomAtticaAccount* >( node->customAccount )->atticaContent(); + const bool hasAttica = !content.id().isNull(); switch ( role ) { @@ -362,15 +369,15 @@ AccountModel::data( const QModelIndex& index, int role ) const return ShippedWithTomahawk; case Qt::ToolTipRole: case DescriptionRole: - return hasAttica ? node->atticaContent.description() : node->factory->description(); + return hasAttica ? content.description() : node->factory->description(); case CanRateRole: return hasAttica; case AuthorRole: - return hasAttica ? node->atticaContent.author() : QString(); + return hasAttica ? content.author() : QString(); case RatingRole: - return hasAttica ? node->atticaContent.rating() / 20 : 0; // rating is out of 100 + return hasAttica ? content.rating() / 20 : 0; // rating is out of 100 case DownloadCounterRole: - return hasAttica ? node->atticaContent.downloads() : QVariant(); + return hasAttica ? content.downloads() : QVariant(); case RowTypeRole: return CustomAccount; case AccountData: @@ -383,6 +390,8 @@ AccountModel::data( const QModelIndex& index, int role ) const return account->enabled() ? Qt::Checked : Qt::Unchecked; case ConnectionStateRole: return account->connectionState(); + case UserHasRatedRole: + return hasAttica ? AtticaManager::instance()->userHasRated( content ) : false; default: return QVariant(); } @@ -459,7 +468,11 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role qDebug() << "Kicked off fetch+install, now waiting"; m_waitingForAtticaInstall.insert( resolver.id() ); - AtticaManager::instance()->installResolver( resolver ); + if ( node->atticaAccount ) + AtticaManager::instance()->installResolverWithHandler( resolver, node->atticaAccount ); + else + AtticaManager::instance()->installResolver( resolver, true ); + return true; } @@ -542,16 +555,25 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( role == RatingRole ) { // We only support rating Attica resolvers for the moment. - Q_ASSERT( node->type == AccountModelNode::AtticaType ); + Attica::Content content; + if ( node->type == AccountModelNode::AtticaType ) + content = node->atticaContent; + else if ( node->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( node->customAccount ) ) + content = qobject_cast< CustomAtticaAccount* >( node->customAccount )->atticaContent(); - AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( node->atticaContent ); + Q_ASSERT( !content.id().isNull() ); + + AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( content ); // For now only allow rating if a resolver is installed! if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade ) return false; - if ( AtticaManager::instance()->userHasRated( node->atticaContent ) ) + if ( AtticaManager::instance()->userHasRated( content ) ) return false; - node->atticaContent.setRating( value.toInt() * 20 ); - AtticaManager::instance()->uploadRating( node->atticaContent ); + content.setRating( value.toInt() * 20 ); + AtticaManager::instance()->uploadRating( content ); + + if ( node->type == AccountModelNode::AtticaType ) + node->atticaContent = content; emit dataChanged( index, index ); diff --git a/src/libtomahawk/accounts/AccountModelNode.h b/src/libtomahawk/accounts/AccountModelNode.h index 857d57402..18486ef8b 100644 --- a/src/libtomahawk/accounts/AccountModelNode.h +++ b/src/libtomahawk/accounts/AccountModelNode.h @@ -139,9 +139,6 @@ struct AccountModelNode { init(); customAccount = account; factory = AccountManager::instance()->factoryForAccount( account ); - - if ( CustomAtticaAccount* customAtticaAccount = qobject_cast< CustomAtticaAccount* >( account ) ) - atticaContent = customAtticaAccount->atticaContent(); } void init() diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 799279df8..4e7921702 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -74,18 +74,12 @@ ResolverAccount::ResolverAccount( const QString& accountId ) { const QString path = configuration()[ "path" ].toString(); + setTypes( AccountType( ResolverType ) ); // We should have a valid saved path Q_ASSERT( !path.isEmpty() ); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( path, enabled() ) ) ); - connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); - - // What resolver do we have here? Should only be types that are 'real' resolvers - Q_ASSERT ( !m_resolver.isNull() ); - - setAccountFriendlyName( m_resolver.data()->name() ); - setTypes( AccountType( ResolverType ) ); + init( path ); } @@ -95,16 +89,8 @@ ResolverAccount::ResolverAccount( const QString& accountId, const QString& path QVariantHash configuration; configuration[ "path" ] = path; setConfiguration( configuration ); - setEnabled( true ); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( path, true ) ) ); - connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); - - // What resolver do we have here? Should only be types that are 'real' resolvers - Q_ASSERT ( m_resolver.data() ); - - setAccountFriendlyName( m_resolver.data()->name() ); - setTypes( AccountType( ResolverType ) ); + init( path ); sync(); } @@ -120,11 +106,41 @@ ResolverAccount::~ResolverAccount() } +void +ResolverAccount::init( const QString& path ) +{ + setTypes( AccountType( ResolverType ) ); + + if ( !QFile::exists( path ) ) + { + AccountManager::instance()->disableAccount( this ); + } + else + { + hookupResolver(); + } +} + + +void +ResolverAccount::hookupResolver() +{ + m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString(), true ) ) ); + connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); + + // What resolver do we have here? Should only be types that are 'real' resolvers + Q_ASSERT ( m_resolver.data() ); + + setAccountFriendlyName( m_resolver.data()->name() ); +} + void ResolverAccount::authenticate() { - Q_ASSERT( !m_resolver.isNull() ); + if ( m_resolver.isNull() ) + return; + qDebug() << Q_FUNC_INFO << "Authenticating/starting resolver, exists?" << m_resolver; if ( !m_resolver.data()->running() ) @@ -137,14 +153,14 @@ ResolverAccount::authenticate() bool ResolverAccount::isAuthenticated() const { - return m_resolver.data()->running(); + return !m_resolver.isNull() && m_resolver.data()->running(); } void ResolverAccount::deauthenticate() { - if ( m_resolver.data()->running() ) + if ( !m_resolver.isNull() && m_resolver.data()->running() ) m_resolver.data()->stop(); emit connectionStateChanged( connectionState() ); @@ -155,7 +171,7 @@ ResolverAccount::deauthenticate() Account::ConnectionState ResolverAccount::connectionState() const { - if ( m_resolver.data()->running() ) + if ( !m_resolver.isNull() && m_resolver.data()->running() ) return Connected; else return Disconnected; @@ -165,6 +181,9 @@ ResolverAccount::connectionState() const QWidget* ResolverAccount::configurationWidget() { + if ( m_resolver.isNull() ) + return 0; + return m_resolver.data()->configUI(); } @@ -189,13 +208,17 @@ ResolverAccount::removeFromConfig() void ResolverAccount::saveConfig() { Account::saveConfig(); - m_resolver.data()->saveConfig(); + if ( !m_resolver.isNull() ) + m_resolver.data()->saveConfig(); } QString ResolverAccount::path() const { + if ( m_resolver.isNull() ) + return QString(); + return m_resolver.data()->filePath(); } @@ -242,6 +265,9 @@ AtticaResolverAccount::~AtticaResolverAccount() void AtticaResolverAccount::loadIcon() { + if ( m_resolver.isNull() ) + return; + const QFileInfo fi( m_resolver.data()->filePath() ); QDir codeDir = fi.absoluteDir(); codeDir.cd( "../images" ); @@ -252,6 +278,19 @@ AtticaResolverAccount::loadIcon() } +void +AtticaResolverAccount::setPath( const QString& path ) +{ + QVariantHash config = configuration(); + config[ "path" ] = path; + setConfiguration( config ); + + hookupResolver(); + + sync(); +} + + QPixmap AtticaResolverAccount::icon() const { diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index bcf167640..fb3f5487e 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -89,8 +89,14 @@ private slots: protected: // Created by factory, when user installs a new resolver ResolverAccount( const QString& accountId, const QString& path ); + + void hookupResolver(); + QWeakPointer m_resolver; +private: + void init( const QString& path ); + friend class ResolverAccountFactory; }; @@ -110,6 +116,8 @@ public: virtual QPixmap icon() const; QString atticaId() const { return m_atticaId; } + + void setPath( const QString& path ); private: // Created by factory, when user installs a new resolver AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId ); From a3d11225a31038691223df43eaaf00516c8fc245 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 09:38:26 +0200 Subject: [PATCH 024/433] * Fixed compiling on OS X 10.6. --- src/libtomahawk/utils/TomahawkUtils_Mac.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/utils/TomahawkUtils_Mac.mm b/src/libtomahawk/utils/TomahawkUtils_Mac.mm index fc5c3d08c..fa82f9d76 100644 --- a/src/libtomahawk/utils/TomahawkUtils_Mac.mm +++ b/src/libtomahawk/utils/TomahawkUtils_Mac.mm @@ -16,17 +16,17 @@ * along with Tomahawk. If not, see . */ -#include "TomahawkUtils.h" - -#include "TomahawkUtils_Mac.h" #include "mac/FileHelpers.h" -#include -#include - #import #import +#include "TomahawkUtils.h" +#include "TomahawkUtils_Mac.h" + +#include +#include + @implementation MoveDelegate From f160947ddc36bc4011fcf15cfcd4aa33d73b2fa7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 10:07:29 +0200 Subject: [PATCH 025/433] * Split out BinaryExtractWorker and SharedTimeLine into separate files. --- src/libtomahawk/CMakeLists.txt | 2 + src/libtomahawk/utils/BinaryExtractWorker.cpp | 104 ++++++++++++++ src/libtomahawk/utils/BinaryExtractWorker.h | 59 ++++++++ src/libtomahawk/utils/PixmapDelegateFader.h | 1 + src/libtomahawk/utils/SharedTimeLine.cpp | 64 +++++++++ src/libtomahawk/utils/SharedTimeLine.h | 60 ++++++++ src/libtomahawk/utils/TomahawkUtils.cpp | 135 +----------------- src/libtomahawk/utils/TomahawkUtils.h | 30 ---- src/libtomahawk/widgets/FadingPixmap.h | 1 + 9 files changed, 294 insertions(+), 162 deletions(-) create mode 100644 src/libtomahawk/utils/BinaryExtractWorker.cpp create mode 100644 src/libtomahawk/utils/BinaryExtractWorker.h create mode 100644 src/libtomahawk/utils/SharedTimeLine.cpp create mode 100644 src/libtomahawk/utils/SharedTimeLine.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 170b72524..1e5029426 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -122,6 +122,8 @@ set( libGuiSources utils/SmartPointerList.h utils/AnimatedSpinner.cpp utils/BinaryInstallerHelper.cpp + utils/BinaryExtractWorker.cpp + utils/SharedTimeLine.cpp widgets/AnimatedCounterLabel.cpp widgets/CheckDirTree.cpp diff --git a/src/libtomahawk/utils/BinaryExtractWorker.cpp b/src/libtomahawk/utils/BinaryExtractWorker.cpp new file mode 100644 index 000000000..f05031c57 --- /dev/null +++ b/src/libtomahawk/utils/BinaryExtractWorker.cpp @@ -0,0 +1,104 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2012, Jeff Mitchell + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "BinaryExtractWorker.h" + +#include +#include +#include + +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" + + +namespace TomahawkUtils +{ + +void +BinaryExtractWorker::run() +{ + ScopedDeleter deleter( this ); + +#ifdef Q_OS_MAC + // Platform-specific handling of resolver payload now. We know it's good + // Unzip the file. + QFileInfo info( m_zipFileName ); + QDir tmpDir = QDir::tempPath(); + if ( !tmpDir.mkdir( info.baseName() ) ) + { + qWarning() << "Failed to create temporary directory to unzip in:" << tmpDir.absolutePath(); + return; + } + tmpDir.cd( info.baseName() ); + TomahawkUtils::unzipFileInFolder( info.absoluteFilePath(), tmpDir ); + + // On OSX it just contains 1 file, the resolver executable itself. For now. We just copy it to + // the Tomahawk.app/Contents/MacOS/ folder alongside the Tomahawk executable. + const QString dest = QCoreApplication::applicationDirPath(); + // Find the filename + const QDir toList( tmpDir.absolutePath() ); + const QStringList files = toList.entryList( QStringList(), QDir::Files ); + Q_ASSERT( files.size() == 1 ); + + const QString src = toList.absoluteFilePath( files.first() ); + qDebug() << "OS X: Copying binary resolver from to:" << src << dest; + + copyWithAuthentication( src, dest, m_receiver ); + + return; +#elif defined(Q_OS_WIN) || defined(Q_OS_LINUX) + // We unzip directly to the target location, just like normal attica resolvers + Q_ASSERT( m_receiver ); + if ( !m_receiver ) + return; + + const QString resolverId = m_receiver->property( "resolverid" ).toString(); + + Q_ASSERT( !resolverId.isEmpty() ); + if ( resolverId.isEmpty() ) + return; + + const QDir resolverPath( extractScriptPayload( m_zipFileName, resolverId ) ); + +#ifdef Q_OS_WIN + const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); +#elif defined(Q_OS_LINUX) + const QStringList files = resolverPath.entryList( QStringList() << "*_tomahawkresolver", QDir::Files ); +#endif + + qDebug() << "Found executables in unzipped binary resolver dir:" << files; + Q_ASSERT( files.size() == 1 ); + if ( files.size() < 1 ) + return; + + const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); + +#ifdef Q_OS_LINUX + QProcess p; + p.start( "chmod", QStringList() << "744" << resolverToUse, QIODevice::ReadOnly ); + p.waitForFinished(); +#endif + + QMetaObject::invokeMethod( m_receiver, "installSucceeded", Qt::QueuedConnection, Q_ARG( QString, resolverToUse ) ); + +#endif +} + +} diff --git a/src/libtomahawk/utils/BinaryExtractWorker.h b/src/libtomahawk/utils/BinaryExtractWorker.h new file mode 100644 index 000000000..52fceb301 --- /dev/null +++ b/src/libtomahawk/utils/BinaryExtractWorker.h @@ -0,0 +1,59 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2012, Jeff Mitchell + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef BINARYEXTRACTWORKER_H +#define BINARYEXTRACTWORKER_H + +#include + +#include "DllMacro.h" + +namespace TomahawkUtils +{ + +class ScopedDeleter +{ +public: + ScopedDeleter( QObject* o ) : m_o( 0 ) {} + ~ScopedDeleter() { m_o->deleteLater(); } + +private: + QObject* m_o; +}; + + +class BinaryExtractWorker : public QThread +{ + Q_OBJECT +public: + BinaryExtractWorker( const QString& zipFilename, QObject* receiver ) : m_zipFileName( zipFilename ), m_receiver( receiver ) {} + virtual ~BinaryExtractWorker() {} + +protected: + virtual void run(); + +private: + QString m_zipFileName; + QObject* m_receiver; +}; + +} + +#endif \ No newline at end of file diff --git a/src/libtomahawk/utils/PixmapDelegateFader.h b/src/libtomahawk/utils/PixmapDelegateFader.h index ee0a71ac7..f79c58774 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.h +++ b/src/libtomahawk/utils/PixmapDelegateFader.h @@ -23,6 +23,7 @@ #include "Artist.h" #include "Album.h" #include "Query.h" +#include "utils/SharedTimeLine.h" #include #include diff --git a/src/libtomahawk/utils/SharedTimeLine.cpp b/src/libtomahawk/utils/SharedTimeLine.cpp new file mode 100644 index 000000000..cb48befed --- /dev/null +++ b/src/libtomahawk/utils/SharedTimeLine.cpp @@ -0,0 +1,64 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2012, Jeff Mitchell + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "SharedTimeLine.h" + + +namespace TomahawkUtils +{ + +SharedTimeLine::SharedTimeLine() + : QObject( 0 ) + , m_refcount( 0 ) +{ + m_timeline.setCurveShape( QTimeLine::LinearCurve ); + m_timeline.setFrameRange( 0, INT_MAX ); + m_timeline.setDuration( INT_MAX ); + m_timeline.setUpdateInterval( 40 ); + connect( &m_timeline, SIGNAL( frameChanged( int ) ), SIGNAL( frameChanged( int ) ) ); +} + + +void +SharedTimeLine::connectNotify( const char* signal ) +{ + if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) { + m_refcount++; + if ( m_timeline.state() != QTimeLine::Running ) + m_timeline.start(); + } +} + + +void +SharedTimeLine::disconnectNotify( const char* signal ) +{ + if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) + { + m_refcount--; + if ( m_timeline.state() == QTimeLine::Running && m_refcount == 0 ) + { + m_timeline.stop(); + deleteLater(); + } + } +} + +} \ No newline at end of file diff --git a/src/libtomahawk/utils/SharedTimeLine.h b/src/libtomahawk/utils/SharedTimeLine.h new file mode 100644 index 000000000..5d8d59602 --- /dev/null +++ b/src/libtomahawk/utils/SharedTimeLine.h @@ -0,0 +1,60 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2012, Jeff Mitchell + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef SHAREDTIMELINE_H +#define SHAREDTIMELINE_H + +#include +#include + +#include "DllMacro.h" + +namespace TomahawkUtils +{ + +class DLLEXPORT SharedTimeLine : public QObject +{ + Q_OBJECT + + public: + SharedTimeLine(); + + virtual ~SharedTimeLine() {} + + int currentFrame() { return m_timeline.currentFrame(); } + + void setUpdateInterval( int msec ) { if ( msec != m_timeline.updateInterval() ) m_timeline.setUpdateInterval( msec ); } + + signals: + void frameChanged( int ); + + protected slots: + virtual void connectNotify( const char *signal ); + + virtual void disconnectNotify( const char *signal ); + + private: + int m_refcount; + QTimeLine m_timeline; +}; + +} + +#endif \ No newline at end of file diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 6560ebc04..5adba5422 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -25,6 +25,8 @@ #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "Source.h" +#include "BinaryExtractWorker.h" +#include "SharedTimeLine.h" #ifdef LIBLASTFM_FOUND #include @@ -55,7 +57,7 @@ #endif #ifdef QCA2_FOUND -#include + #include #endif namespace TomahawkUtils @@ -648,43 +650,6 @@ crash() } -SharedTimeLine::SharedTimeLine() - : QObject( 0 ) - , m_refcount( 0 ) -{ - m_timeline.setCurveShape( QTimeLine::LinearCurve ); - m_timeline.setFrameRange( 0, INT_MAX ); - m_timeline.setDuration( INT_MAX ); - m_timeline.setUpdateInterval( 40 ); - connect( &m_timeline, SIGNAL( frameChanged( int ) ), SIGNAL( frameChanged( int ) ) ); -} - -void -SharedTimeLine::connectNotify( const char* signal ) -{ - if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) { - m_refcount++; - if ( m_timeline.state() != QTimeLine::Running ) - m_timeline.start(); - } -} - - -void -SharedTimeLine::disconnectNotify( const char* signal ) -{ - if ( signal == QMetaObject::normalizedSignature( SIGNAL( frameChanged( int ) ) ) ) - { - m_refcount--; - if ( m_timeline.state() == QTimeLine::Running && m_refcount == 0 ) - { - m_timeline.stop(); - deleteLater(); - } - } -} - - bool verifyFile( const QString &filePath, const QString &signature ) { @@ -772,7 +737,6 @@ extractScriptPayload( const QString& filename, const QString& resolverId ) } resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) ); - if ( !unzipFileInFolder( filename, resolverDir ) ) { qWarning() << "Failed to unzip resolver. Ooops."; @@ -846,99 +810,6 @@ unzipFileInFolder( const QString &zipFileName, const QDir &folder ) } -class ScopedDeleter -{ -public: - ScopedDeleter( QObject* o ) : m_o( 0 ) {} - ~ScopedDeleter() { m_o->deleteLater(); } - -private: - QObject* m_o; -}; - - -class BinaryExtractWorker : public QThread -{ - Q_OBJECT -public: - BinaryExtractWorker( const QString& zipFilename, QObject* receiver ) : m_zipFileName( zipFilename ), m_receiver( receiver ) {} - virtual ~BinaryExtractWorker() {} - -protected: - virtual void run() - { - ScopedDeleter deleter( this ); - -#ifdef Q_OS_MAC - // Platform-specific handling of resolver payload now. We know it's good - // Unzip the file. - QFileInfo info( m_zipFileName ); - QDir tmpDir = QDir::tempPath(); - if ( !tmpDir.mkdir( info.baseName() ) ) - { - qWarning() << "Failed to create temporary directory to unzip in:" << tmpDir.absolutePath(); - return; - } - tmpDir.cd( info.baseName() ); - TomahawkUtils::unzipFileInFolder( info.absoluteFilePath(), tmpDir ); - - // On OSX it just contains 1 file, the resolver executable itself. For now. We just copy it to - // the Tomahawk.app/Contents/MacOS/ folder alongside the Tomahawk executable. - const QString dest = QCoreApplication::applicationDirPath(); - // Find the filename - const QDir toList( tmpDir.absolutePath() ); - const QStringList files = toList.entryList( QStringList(), QDir::Files ); - Q_ASSERT( files.size() == 1 ); - - const QString src = toList.absoluteFilePath( files.first() ); - qDebug() << "OS X: Copying binary resolver from to:" << src << dest; - - copyWithAuthentication( src, dest, m_receiver ); - - return; -#elif defined(Q_OS_WIN) || defined(Q_OS_LINUX) - // We unzip directly to the target location, just like normal attica resolvers - Q_ASSERT( m_receiver ); - if ( !m_receiver ) - return; - - const QString resolverId = m_receiver->property( "resolverid" ).toString(); - - Q_ASSERT( !resolverId.isEmpty() ); - if ( resolverId.isEmpty() ) - return; - - - const QDir resolverPath( extractScriptPayload( m_zipFileName, resolverId ) ); - -#ifdef Q_OS_WIN - const QStringList files = resolverPath.entryList( QStringList() << "*.exe", QDir::Files ); -#elif defined(Q_OS_LINUX) - const QStringList files = resolverPath.entryList( QStringList() << "*_tomahawkresolver", QDir::Files ); -#endif - - qDebug() << "Found executables in unzipped binary resolver dir:" << files; - Q_ASSERT( files.size() == 1 ); - if ( files.size() < 1 ) - return; - - const QString resolverToUse = resolverPath.absoluteFilePath( files.first() ); - -#ifdef Q_OS_LINUX - QProcess p; - p.start( "chmod", QStringList() << "744" << resolverToUse, QIODevice::ReadOnly ); - p.waitForFinished(); -#endif - - QMetaObject::invokeMethod( m_receiver, "installSucceeded", Qt::QueuedConnection, Q_ARG( QString, resolverToUse ) ); - -#endif - } -private: - QString m_zipFileName; - QObject* m_receiver; -}; - void extractBinaryResolver( const QString& zipFilename, QObject* receiver ) { diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index 27350e3e1..c3b256ca2 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -26,12 +26,10 @@ #include #include #include -#include #include #define RESPATH ":/data/" - class QDir; class QNetworkAccessManager; @@ -64,33 +62,6 @@ namespace TomahawkUtils }; - class DLLEXPORT SharedTimeLine : public QObject - { - Q_OBJECT - - public: - SharedTimeLine(); - - virtual ~SharedTimeLine() {} - - int currentFrame() { return m_timeline.currentFrame(); } - - void setUpdateInterval( int msec ) { if ( msec != m_timeline.updateInterval() ) m_timeline.setUpdateInterval( msec ); } - - signals: - void frameChanged( int ); - - protected slots: - virtual void connectNotify( const char *signal ); - - virtual void disconnectNotify( const char *signal ); - - private: - int m_refcount; - QTimeLine m_timeline; - }; - - class DLLEXPORT NetworkProxyFactory : public QNetworkProxyFactory { public: @@ -143,7 +114,6 @@ namespace TomahawkUtils DLLEXPORT QString extractScriptPayload( const QString& filename, const QString& resolverId ); DLLEXPORT bool unzipFileInFolder( const QString& zipFileName, const QDir& folder ); - // Extracting may be asynchronous, pass in a receiver object with the following slots: // extractSucceeded( const QString& path ) and extractFailed() to be notified/ DLLEXPORT void extractBinaryResolver( const QString& zipFilename, QObject* receiver ); diff --git a/src/libtomahawk/widgets/FadingPixmap.h b/src/libtomahawk/widgets/FadingPixmap.h index 9096e2a40..5e4928817 100644 --- a/src/libtomahawk/widgets/FadingPixmap.h +++ b/src/libtomahawk/widgets/FadingPixmap.h @@ -20,6 +20,7 @@ #ifndef FADINGPIXMAP_H #define FADINGPIXMAP_H +#include "utils/SharedTimeLine.h" #include "utils/TomahawkUtils.h" #include From ff70417891bb9270b57b4a27d1f4baa11d854de5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 10:15:47 +0200 Subject: [PATCH 026/433] * Progress towards compiling on OS X (10.6). --- src/libtomahawk/utils/BinaryExtractWorker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/utils/BinaryExtractWorker.cpp b/src/libtomahawk/utils/BinaryExtractWorker.cpp index f05031c57..0c4353676 100644 --- a/src/libtomahawk/utils/BinaryExtractWorker.cpp +++ b/src/libtomahawk/utils/BinaryExtractWorker.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "utils/TomahawkUtils.h" #include "utils/Logger.h" From 5d0a54ce8b607e570c034a8fff347c35d908b403 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 12:18:42 +0200 Subject: [PATCH 027/433] * Moved TomahawkSqlQuery's implementation into a separate file. --- src/libtomahawk/CMakeLists.txt | 2 +- src/libtomahawk/database/TomahawkSqlQuery.cpp | 76 +++++++++++++++++++ src/libtomahawk/database/TomahawkSqlQuery.h | 51 ++----------- 3 files changed, 83 insertions(+), 46 deletions(-) create mode 100644 src/libtomahawk/database/TomahawkSqlQuery.cpp diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 1e5029426..4a1f0c049 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -197,7 +197,6 @@ set( libSources audio/AudioEngine.cpp - database/Database.cpp database/FuzzyIndex.cpp database/DatabaseCollection.cpp @@ -250,6 +249,7 @@ set( libSources database/DatabaseCommand_TrackAttributes.cpp database/DatabaseCommand_SetTrackAttributes.cpp database/Database.cpp + database/TomahawkSqlQuery.cpp infosystem/InfoSystem.cpp infosystem/InfoSystemCache.cpp diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp new file mode 100644 index 000000000..faf832625 --- /dev/null +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -0,0 +1,76 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "database/TomahawkSqlQuery.h" + +#include "utils/Logger.h" + +#include +#include + +#define QUERY_THRESHOLD 60 + + +TomahawkSqlQuery::TomahawkSqlQuery() + : QSqlQuery() +{ +} + + +TomahawkSqlQuery::TomahawkSqlQuery( const QSqlDatabase& db ) + : QSqlQuery( db ) +{ +} + + +bool +TomahawkSqlQuery::exec( const QString& query ) +{ + prepare( query ); + return exec(); +} + + +bool +TomahawkSqlQuery::exec() +{ + QTime t; + t.start(); + + bool ret = QSqlQuery::exec(); + if ( !ret ) + showError(); + + int e = t.elapsed(); + if ( e >= QUERY_THRESHOLD ) + tLog() << "TomahawkSqlQuery (" << lastQuery() << ") finished in" << t.elapsed() << "ms"; + + return ret; +} + + +void +TomahawkSqlQuery::showError() +{ + tLog() << "\n" << "*** DATABASE ERROR ***" << "\n" + << this->lastQuery() << "\n" + << "boundValues:" << this->boundValues() << "\n" + << this->lastError().text() << "\n" + ; + Q_ASSERT( false ); +} diff --git a/src/libtomahawk/database/TomahawkSqlQuery.h b/src/libtomahawk/database/TomahawkSqlQuery.h index b88d56eb8..ef078f612 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.h +++ b/src/libtomahawk/database/TomahawkSqlQuery.h @@ -18,62 +18,23 @@ #ifndef TOMAHAWKSQLQUERY_H #define TOMAHAWKSQLQUERY_H + // subclass QSqlQuery so that it prints the error msg if a query fails #include -#include -#include - -#include "utils/Logger.h" - -#define TOMAHAWK_QUERY_THRESHOLD 60 class TomahawkSqlQuery : public QSqlQuery { public: + TomahawkSqlQuery(); + TomahawkSqlQuery( const QSqlDatabase& db ); - TomahawkSqlQuery() - : QSqlQuery() - {} - - TomahawkSqlQuery( const QSqlDatabase& db ) - : QSqlQuery( db ) - {} - - bool exec( const QString& query ) - { - prepare( query ); - - return exec(); - } - - bool exec() - { - QTime t; - t.start(); - - bool ret = QSqlQuery::exec(); - if( !ret ) - showError(); - - int e = t.elapsed(); - if ( e >= TOMAHAWK_QUERY_THRESHOLD ) - tLog( LOGVERBOSE ) << "TomahawkSqlQuery (" << lastQuery() << ") finished in" << t.elapsed() << "ms"; - - return ret; - } + bool exec( const QString& query ); + bool exec(); private: - void showError() - { - tLog() << "\n" << "*** DATABASE ERROR ***" << "\n" - << this->lastQuery() << "\n" - << "boundValues:" << this->boundValues() << "\n" - << this->lastError().text() << "\n" - ; - Q_ASSERT( false ); - } + void showError(); }; #endif // TOMAHAWKSQLQUERY_H From 3e1a5c15c56077834a1a88e6fd08294f749a9fea Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 12:41:02 +0200 Subject: [PATCH 028/433] * Added verbose log output for SQL queries. --- src/libtomahawk/database/TomahawkSqlQuery.cpp | 12 +++++++--- src/libtomahawk/utils/Logger.cpp | 11 +++++++++ src/libtomahawk/utils/Logger.h | 24 +++++++++++++------ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp index faf832625..f014cd0c4 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.cpp +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -24,6 +24,7 @@ #include #define QUERY_THRESHOLD 60 +#define QUERY_ANALYZE 1 TomahawkSqlQuery::TomahawkSqlQuery() @@ -57,9 +58,14 @@ TomahawkSqlQuery::exec() showError(); int e = t.elapsed(); - if ( e >= QUERY_THRESHOLD ) - tLog() << "TomahawkSqlQuery (" << lastQuery() << ") finished in" << t.elapsed() << "ms"; - + bool log = ( e >= QUERY_THRESHOLD ); +#ifdef QUERY_ANALYZE + log = true; +#endif + + if ( log ) + tLog( LOGSQL ) << "TomahawkSqlQuery (" << t.elapsed() << "ms ):" << lastQuery(); + return ret; } diff --git a/src/libtomahawk/utils/Logger.cpp b/src/libtomahawk/utils/Logger.cpp index 4f4efd7f5..a34df872d 100644 --- a/src/libtomahawk/utils/Logger.cpp +++ b/src/libtomahawk/utils/Logger.cpp @@ -35,6 +35,7 @@ #define RELEASE_LEVEL_THRESHOLD 0 #define DEBUG_LEVEL_THRESHOLD LOGEXTRA +#define LOG_SQL_QUERIES 1 using namespace std; ofstream logfile; @@ -65,9 +66,19 @@ log( const char *msg, unsigned int debugLevel, bool toDisk = true ) if ( debugLevel > DEBUG_LEVEL_THRESHOLD ) toDisk = false; #endif + + #ifdef LOG_SQL_QUERIES + if ( debugLevel == LOGSQL ) + toDisk = true; + #endif if ( toDisk || (int)debugLevel <= s_threshold ) { + #ifdef LOG_SQL_QUERIES + if ( debugLevel == LOGSQL ) + logfile << "TSQLQUERY: "; + #endif + logfile << QTime::currentTime().toString().toAscii().data() << " [" << QString::number( debugLevel ).toAscii().data() << "]: " << msg << endl; logfile.flush(); } diff --git a/src/libtomahawk/utils/Logger.h b/src/libtomahawk/utils/Logger.h index a95fee6ef..6c1f69fdb 100644 --- a/src/libtomahawk/utils/Logger.h +++ b/src/libtomahawk/utils/Logger.h @@ -24,6 +24,13 @@ #include "DllMacro.h" +#define LOGDEBUG 1 +#define LOGINFO 2 +#define LOGEXTRA 5 +#define LOGVERBOSE 8 +#define LOGTHIRDPARTY 9 +#define LOGSQL 10 + namespace Logger { class DLLEXPORT TLog : public QDebug @@ -40,7 +47,15 @@ namespace Logger class DLLEXPORT TDebug : public TLog { public: - TDebug( unsigned int debugLevel = 1 ) : TLog( debugLevel ) + TDebug( unsigned int debugLevel = LOGDEBUG ) : TLog( debugLevel ) + { + } + }; + + class DLLEXPORT TSqlLog : public TLog + { + public: + TSqlLog() : TLog( LOGSQL ) { } }; @@ -51,11 +66,6 @@ namespace Logger #define tLog Logger::TLog #define tDebug Logger::TDebug - -#define LOGDEBUG 1 -#define LOGINFO 2 -#define LOGEXTRA 5 -#define LOGVERBOSE 8 -#define LOGTHIRDPARTY 9 +#define tSqlLog Logger::TSqlLog #endif // TOMAHAWK_LOGGER_H From 26736459073374986c7adb1939f75f2701849b66 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 13:04:30 +0200 Subject: [PATCH 029/433] * Fixed compiling on OSX. --- src/libtomahawk/database/TomahawkSqlQuery.cpp | 8 ++++---- src/libtomahawk/database/TomahawkSqlQuery.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp index f014cd0c4..5a5ea628a 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.cpp +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -22,9 +22,9 @@ #include #include +#include #define QUERY_THRESHOLD 60 -#define QUERY_ANALYZE 1 TomahawkSqlQuery::TomahawkSqlQuery() @@ -59,7 +59,7 @@ TomahawkSqlQuery::exec() int e = t.elapsed(); bool log = ( e >= QUERY_THRESHOLD ); -#ifdef QUERY_ANALYZE +#ifdef TOMAHAWK_QUERY_ANALYZE log = true; #endif @@ -76,7 +76,7 @@ TomahawkSqlQuery::showError() tLog() << "\n" << "*** DATABASE ERROR ***" << "\n" << this->lastQuery() << "\n" << "boundValues:" << this->boundValues() << "\n" - << this->lastError().text() << "\n" - ; + << this->lastError().text() << "\n"; + Q_ASSERT( false ); } diff --git a/src/libtomahawk/database/TomahawkSqlQuery.h b/src/libtomahawk/database/TomahawkSqlQuery.h index ef078f612..8bf1a1495 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.h +++ b/src/libtomahawk/database/TomahawkSqlQuery.h @@ -23,6 +23,8 @@ #include +#define TOMAHAWK_QUERY_ANALYZE 1 + class TomahawkSqlQuery : public QSqlQuery { From e2ab7d834b24ffc5811698ea9ed12489330e5d71 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 13:08:23 +0200 Subject: [PATCH 030/433] * Run analyze on shutdown (for debugging only). --- src/libtomahawk/database/DatabaseImpl.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index d51ecea8a..67c7bf3b8 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -96,6 +96,18 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) DatabaseImpl::~DatabaseImpl() { delete m_fuzzyIndex; + +#ifdef TOMAHAWK_QUERY_ANALYZE + TomahawkSqlQuery q = newquery(); + + q.exec( "ANALYZE" ); + q.exec( "SELECT * FROM sqlite_stat1" ); + while ( q.next() ) + { + tLog( LOGSQL ) << q.value( 0 ).toString() << q.value( 1 ).toString() << q.value( 2 ).toString(); + } + +#endif } From bc0e3810d7fb2a229438c67ff0f5f43880801ae4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 14:29:17 +0200 Subject: [PATCH 031/433] * Speed up DbCmd_AllAlbums. A ton. --- src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp index 5f7e8a396..c97fcf558 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp @@ -77,7 +77,7 @@ DatabaseCommand_AllAlbums::execForArtist( DatabaseImpl* dbi ) } filterToken = QString( "AND artist.id = file_join.artist AND file_join.track = track.id %1" ).arg( filtersql ); - tables = "artist, track, file, file_join"; + tables = "file, file_join, artist, track"; } else tables = "file, file_join"; @@ -139,7 +139,7 @@ DatabaseCommand_AllAlbums::execForCollection( DatabaseImpl* dbi ) QString sql = QString( "SELECT DISTINCT album.id, album.name, album.artist, artist.name " - "FROM album, file, file_join " + "FROM file, file_join, album " "LEFT OUTER JOIN artist ON album.artist = artist.id " "WHERE file.id = file_join.file " "AND file_join.album = album.id " From ab602b207250ad4d365236e2e36b51c5645e6126 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 16:54:50 +0200 Subject: [PATCH 032/433] * Don't tell model about item size if there's no model yet. --- src/libtomahawk/playlist/AlbumView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 779afd97f..015fb6af9 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -195,7 +195,7 @@ AlbumView::resizeEvent( QResizeEvent* event ) { QListView::resizeEvent( event ); - if ( autoFitItems() ) + if ( autoFitItems() && m_model ) { #ifdef Q_WS_X11 // int scrollbar = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() + 16 : 0; @@ -215,6 +215,7 @@ AlbumView::resizeEvent( QResizeEvent* event ) int remSpace = rectWidth - ( itemsPerRow * itemWidth ); int extraSpace = remSpace / itemsPerRow; int newItemWidth = itemWidth + extraSpace; + m_model->setItemSize( QSize( newItemWidth, newItemWidth ) ); if ( !m_inited ) From 7af615dbf89fa56ae8956c2aef78e997afaa38b5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 17:08:29 +0200 Subject: [PATCH 033/433] * Disable shutdown db analyze again. --- src/libtomahawk/database/DatabaseImpl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 67c7bf3b8..00002284a 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -96,7 +96,8 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) DatabaseImpl::~DatabaseImpl() { delete m_fuzzyIndex; - + +/* #ifdef TOMAHAWK_QUERY_ANALYZE TomahawkSqlQuery q = newquery(); @@ -108,6 +109,7 @@ DatabaseImpl::~DatabaseImpl() } #endif +*/ } From 0fb151190476f2dc63eb11727b9a6446a210644e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 17:13:58 +0200 Subject: [PATCH 034/433] * Re-layout item grid when model changes. --- src/libtomahawk/playlist/AlbumView.cpp | 9 +++++++++ src/libtomahawk/playlist/AlbumView.h | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 015fb6af9..8ac620a16 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -72,6 +72,8 @@ AlbumView::AlbumView( QWidget* parent ) connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); + connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); + connect( proxyModel(), SIGNAL( modelReset() ), SLOT( layoutItems() ) ); // connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); } @@ -106,6 +108,7 @@ AlbumView::setModel( QAbstractItemModel* model ) void AlbumView::setAlbumModel( AlbumModel* model ) { + m_inited = false; m_model = model; if ( m_proxyModel ) @@ -194,7 +197,13 @@ void AlbumView::resizeEvent( QResizeEvent* event ) { QListView::resizeEvent( event ); + layoutItems(); +} + +void +AlbumView::layoutItems() +{ if ( autoFitItems() && m_model ) { #ifdef Q_WS_X11 diff --git a/src/libtomahawk/playlist/AlbumView.h b/src/libtomahawk/playlist/AlbumView.h index e72b2fa2a..f861846c9 100644 --- a/src/libtomahawk/playlist/AlbumView.h +++ b/src/libtomahawk/playlist/AlbumView.h @@ -90,9 +90,9 @@ private slots: void onFilterChanged( const QString& filter ); void onCustomContextMenu( const QPoint& pos ); -private: - void adjustItemSize( const QRect& rect ); + void layoutItems(); +private: AlbumModel* m_model; AlbumProxyModel* m_proxyModel; AlbumItemDelegate* m_delegate; From 3159cfd84029a1d505e09527cf85ccb198258eaa Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 23 May 2012 11:15:36 -0400 Subject: [PATCH 035/433] Make the Tomahawk cache spit out a more useful error when data not found, and stop Sources from endlessely querying it for avatars that we already know don't exist --- src/libtomahawk/Source.cpp | 7 +++++-- src/libtomahawk/Source.h | 3 ++- src/libtomahawk/utils/TomahawkCache.cpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index cd625a06b..232237054 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -48,6 +48,7 @@ Source::Source( int id, const QString& username ) , m_username( username ) , m_id( id ) , m_updateIndexWhenSynced( false ) + , m_avatarUpdated( true ) , m_state( DBSyncConnection::UNKNOWN ) , m_cc( 0 ) , m_commandCount( 0 ) @@ -136,13 +137,14 @@ Source::setAvatar( const QPixmap& avatar ) tDebug() << Q_FUNC_INFO << friendlyName() << m_username << ba.count(); TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, m_username, ba ); + m_avatarUpdated = true; } QPixmap -Source::avatar( AvatarStyle style, const QSize& size ) const +Source::avatar( AvatarStyle style, const QSize& size ) { - if ( !m_avatar ) + if ( !m_avatar && m_avatarUpdated ) { m_avatar = new QPixmap(); QByteArray ba = TomahawkUtils::Cache::instance()->getData( "Sources", m_username ).toByteArray(); @@ -154,6 +156,7 @@ Source::avatar( AvatarStyle style, const QSize& size ) const delete m_avatar; m_avatar = 0; } + m_avatarUpdated = false; } if ( style == FancyStyle && m_avatar && !m_fancyAvatar ) diff --git a/src/libtomahawk/Source.h b/src/libtomahawk/Source.h index cd45bbc83..883b605dc 100644 --- a/src/libtomahawk/Source.h +++ b/src/libtomahawk/Source.h @@ -66,7 +66,7 @@ public: #ifndef ENABLE_HEADLESS void setAvatar( const QPixmap& avatar ); - QPixmap avatar( AvatarStyle style = Original, const QSize& size = QSize() ) const; + QPixmap avatar( AvatarStyle style = Original, const QSize& size = QSize() ); #endif collection_ptr collection() const; @@ -147,6 +147,7 @@ private: int m_id; bool m_scrubFriendlyName; bool m_updateIndexWhenSynced; + bool m_avatarUpdated; Tomahawk::query_ptr m_currentTrack; QString m_textStatus; diff --git a/src/libtomahawk/utils/TomahawkCache.cpp b/src/libtomahawk/utils/TomahawkCache.cpp index e69baac16..51e58f313 100644 --- a/src/libtomahawk/utils/TomahawkCache.cpp +++ b/src/libtomahawk/utils/TomahawkCache.cpp @@ -101,7 +101,7 @@ QVariant Cache::getData ( const QString& identifier, const QString& key ) return data.data; } - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "No such client" << identifier; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "No such key" << key; return QVariant(); } From 91024493ee9a9ada12d876b0c76de869bd3b376f Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 23 May 2012 11:27:37 -0400 Subject: [PATCH 036/433] Loaded plugins don't get loaded into the correct thread...fix this --- src/infoplugins/generic/hypem/HypemPlugin.cpp | 2 ++ src/libtomahawk/infosystem/InfoSystemWorker.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/infoplugins/generic/hypem/HypemPlugin.cpp b/src/infoplugins/generic/hypem/HypemPlugin.cpp index c4c3a23a1..20d92962b 100644 --- a/src/infoplugins/generic/hypem/HypemPlugin.cpp +++ b/src/infoplugins/generic/hypem/HypemPlugin.cpp @@ -30,6 +30,7 @@ #include "Typedefs.h" #include "TomahawkSettings.h" #include "utils/TomahawkUtils.h" +#include "infosystem/InfoSystemWorker.h" #include "utils/Logger.h" #include "Source.h" @@ -189,6 +190,7 @@ HypemPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData reque void HypemPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) { + tDebug( LOGVERBOSE ) << "HypemPlugin thread: " << QThread::currentThread() << ", InfoSystemWorker thread: " << Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data()->currentThread(); switch ( requestData.type ) { case InfoChart: diff --git a/src/libtomahawk/infosystem/InfoSystemWorker.cpp b/src/libtomahawk/infosystem/InfoSystemWorker.cpp index d80e3c594..f84b55bbd 100644 --- a/src/libtomahawk/infosystem/InfoSystemWorker.cpp +++ b/src/libtomahawk/infosystem/InfoSystemWorker.cpp @@ -96,6 +96,7 @@ InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) return; } + plugin.data()->moveToThread( this->thread() ); m_plugins.append( plugin ); registerInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() ); From d7a925d11003bbfbb3d8aafb7dbe86c50c4537e7 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 23 May 2012 12:31:00 -0400 Subject: [PATCH 037/433] Make init methods for all infoplugins to solve issues with network traffic before they're in the right thread --- src/accounts/lastfm/LastFmAccount.cpp | 1 - src/accounts/lastfm/LastFmInfoPlugin.h | 2 +- src/accounts/twitter/TwitterAccount.cpp | 1 - src/accounts/twitter/TwitterInfoPlugin.h | 2 +- src/accounts/xmpp/XmppInfoPlugin.h | 2 +- src/accounts/xmpp/sip/XmppSip.cpp | 1 - .../generic/charts/ChartsPlugin.cpp | 35 ++++++++++++------- src/infoplugins/generic/charts/ChartsPlugin.h | 1 + .../generic/echonest/EchonestPlugin.cpp | 8 ++++- .../generic/echonest/EchonestPlugin.h | 2 ++ src/infoplugins/generic/hypem/HypemPlugin.cpp | 9 +++-- src/infoplugins/generic/hypem/HypemPlugin.h | 1 + .../generic/musicbrainz/MusicBrainzPlugin.h | 1 + .../generic/musixmatch/MusixMatchPlugin.h | 1 + .../generic/newreleases/NewReleasesPlugin.cpp | 15 +++++--- .../generic/newreleases/NewReleasesPlugin.h | 1 + src/infoplugins/generic/rovi/RoviPlugin.h | 2 ++ .../generic/spotify/SpotifyPlugin.h | 1 + .../linux/fdonotify/FdoNotifyPlugin.h | 2 ++ src/infoplugins/linux/mpris/MprisPlugin.cpp | 15 +++++--- src/infoplugins/linux/mpris/MprisPlugin.h | 2 ++ src/infoplugins/mac/adium/AdiumPlugin.h | 2 ++ src/libtomahawk/infosystem/InfoSystem.h | 12 +++++++ .../infosystem/InfoSystemWorker.cpp | 2 ++ src/libtomahawk/utils/TomahawkUtils.cpp | 9 ++++- 25 files changed, 97 insertions(+), 33 deletions(-) diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index 25364e3e3..7cfbd8924 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -75,7 +75,6 @@ LastFmAccount::LastFmAccount( const QString& accountId ) { infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } } diff --git a/src/accounts/lastfm/LastFmInfoPlugin.h b/src/accounts/lastfm/LastFmInfoPlugin.h index 443192b03..0e5024fee 100644 --- a/src/accounts/lastfm/LastFmInfoPlugin.h +++ b/src/accounts/lastfm/LastFmInfoPlugin.h @@ -51,7 +51,6 @@ public: virtual ~LastFmInfoPlugin(); public slots: - void init(); void settingsChanged(); void onAuthenticated(); @@ -63,6 +62,7 @@ public slots: void similarTracksReturned(); protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/accounts/twitter/TwitterAccount.cpp b/src/accounts/twitter/TwitterAccount.cpp index 91dce3ca1..852968c31 100644 --- a/src/accounts/twitter/TwitterAccount.cpp +++ b/src/accounts/twitter/TwitterAccount.cpp @@ -130,7 +130,6 @@ TwitterAccount::authenticateSlot() { infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } } diff --git a/src/accounts/twitter/TwitterInfoPlugin.h b/src/accounts/twitter/TwitterInfoPlugin.h index e1b221105..0919515b7 100644 --- a/src/accounts/twitter/TwitterInfoPlugin.h +++ b/src/accounts/twitter/TwitterInfoPlugin.h @@ -44,7 +44,6 @@ namespace Tomahawk { virtual ~TwitterInfoPlugin(); public slots: - void init(); void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( criteria ); @@ -52,6 +51,7 @@ namespace Tomahawk { } protected slots: + void init(); void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ); void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { diff --git a/src/accounts/xmpp/XmppInfoPlugin.h b/src/accounts/xmpp/XmppInfoPlugin.h index f553b43d0..cbb248e6d 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.h +++ b/src/accounts/xmpp/XmppInfoPlugin.h @@ -42,10 +42,10 @@ namespace Tomahawk { void publishTune( QUrl url, Tomahawk::InfoSystem::InfoStringHash trackInfo ); public slots: - void init(); void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); protected slots: + void init(); void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ); void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/accounts/xmpp/sip/XmppSip.cpp b/src/accounts/xmpp/sip/XmppSip.cpp index 6330d39c8..036d1f1be 100644 --- a/src/accounts/xmpp/sip/XmppSip.cpp +++ b/src/accounts/xmpp/sip/XmppSip.cpp @@ -293,7 +293,6 @@ XmppSipPlugin::onConnect() { infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); - QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection ); } //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P diff --git a/src/infoplugins/generic/charts/ChartsPlugin.cpp b/src/infoplugins/generic/charts/ChartsPlugin.cpp index 3a3433fb4..20123c997 100644 --- a/src/infoplugins/generic/charts/ChartsPlugin.cpp +++ b/src/infoplugins/generic/charts/ChartsPlugin.cpp @@ -52,8 +52,23 @@ ChartsPlugin::ChartsPlugin() : InfoPlugin() , m_chartsFetchJobs( 0 ) { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QThread::currentThread(); /// If you add resource, update version aswell m_chartVersion = "2.3"; + m_supportedGetTypes << InfoChart << InfoChartCapabilities; +} + + +ChartsPlugin::~ChartsPlugin() +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QThread::currentThread(); +} + + +void +ChartsPlugin::init() +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << QThread::currentThread(); QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "ChartsPlugin", "chart_sources" ).toList(); foreach( const QVariant & source, source_qvarlist ) { m_chartResources.append( source.toString() ); @@ -63,14 +78,6 @@ ChartsPlugin::ChartsPlugin() tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "total sources" << m_chartResources.size() << source_qvarlist.size(); if( m_chartResources.size() == 0 ) fetchChartSourcesList( true ); - m_supportedGetTypes << InfoChart << InfoChartCapabilities; - -} - - -ChartsPlugin::~ChartsPlugin() -{ - tDebug( LOGVERBOSE ) << Q_FUNC_INFO; } @@ -219,7 +226,7 @@ ChartsPlugin::fetchChartSourcesList( bool fetchOnlySourceList ) reply->setProperty( "only_source_list", fetchOnlySourceList ); - tDebug() << "fetching:" << url; + tDebug() << Q_FUNC_INFO << "fetching:" << url; connect( reply, SIGNAL( finished() ), SLOT( chartSourcesList() ) ); } @@ -227,7 +234,7 @@ ChartsPlugin::fetchChartSourcesList( bool fetchOnlySourceList ) void ChartsPlugin::chartSourcesList() { - tDebug( LOGVERBOSE ) << "Got chart sources list"; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got chart sources list"; QNetworkReply* reply = qobject_cast( sender() ); if ( reply->error() == QNetworkReply::NoError ) @@ -239,7 +246,7 @@ ChartsPlugin::chartSourcesList() if ( !ok ) { - tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); + tLog() << Q_FUNC_INFO << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine(); return; } @@ -253,6 +260,8 @@ ChartsPlugin::chartSourcesList() if( !reply->property("only_source_list" ).toBool() ) fetchAllChartSources(); } + else + tDebug() << Q_FUNC_INFO << "Encountered error fetching chart sources list"; } void ChartsPlugin::fetchAllChartSources() @@ -266,7 +275,7 @@ void ChartsPlugin::fetchAllChartSources() QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); reply->setProperty( "chart_source", source); - tDebug() << "fetching:" << url; + tDebug() << Q_FUNC_INFO << "fetching:" << url; connect( reply, SIGNAL( finished() ), SLOT( chartsList() ) ); m_chartsFetchJobs++; @@ -291,7 +300,7 @@ void ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData void ChartsPlugin::chartsList() { - tDebug( LOGVERBOSE ) << "Got chart list result"; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got chart list result"; QNetworkReply* reply = qobject_cast( sender() ); if ( reply->error() == QNetworkReply::NoError ) diff --git a/src/infoplugins/generic/charts/ChartsPlugin.h b/src/infoplugins/generic/charts/ChartsPlugin.h index d521bb19a..bc0fbacfe 100644 --- a/src/infoplugins/generic/charts/ChartsPlugin.h +++ b/src/infoplugins/generic/charts/ChartsPlugin.h @@ -55,6 +55,7 @@ public: ChartType chartType() const { return m_chartType; } protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/infoplugins/generic/echonest/EchonestPlugin.cpp b/src/infoplugins/generic/echonest/EchonestPlugin.cpp index f1d28b89a..b0e1ec65c 100644 --- a/src/infoplugins/generic/echonest/EchonestPlugin.cpp +++ b/src/infoplugins/generic/echonest/EchonestPlugin.cpp @@ -39,7 +39,6 @@ EchonestPlugin::EchonestPlugin() { qDebug() << Q_FUNC_INFO; m_supportedGetTypes << Tomahawk::InfoSystem::InfoArtistBiography << Tomahawk::InfoSystem::InfoArtistFamiliarity << Tomahawk::InfoSystem::InfoArtistHotttness << Tomahawk::InfoSystem::InfoArtistTerms << Tomahawk::InfoSystem::InfoMiscTopTerms; - Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); } @@ -49,6 +48,13 @@ EchonestPlugin::~EchonestPlugin() } +void +EchonestPlugin::init() +{ + Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); +} + + void EchonestPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { diff --git a/src/infoplugins/generic/echonest/EchonestPlugin.h b/src/infoplugins/generic/echonest/EchonestPlugin.h index 4468c375c..bdd4e6a3a 100644 --- a/src/infoplugins/generic/echonest/EchonestPlugin.h +++ b/src/infoplugins/generic/echonest/EchonestPlugin.h @@ -45,6 +45,8 @@ public: virtual ~EchonestPlugin(); protected slots: + virtual void init(); + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/hypem/HypemPlugin.cpp b/src/infoplugins/generic/hypem/HypemPlugin.cpp index 20d92962b..4827d425c 100644 --- a/src/infoplugins/generic/hypem/HypemPlugin.cpp +++ b/src/infoplugins/generic/hypem/HypemPlugin.cpp @@ -95,8 +95,6 @@ HypemPlugin::HypemPlugin() << "Techno" << "Punk" << "New wave"; - chartTypes(); - } @@ -108,6 +106,13 @@ HypemPlugin::~HypemPlugin() } +void +HypemPlugin::init() +{ + chartTypes(); +} + + void HypemPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData ) { diff --git a/src/infoplugins/generic/hypem/HypemPlugin.h b/src/infoplugins/generic/hypem/HypemPlugin.h index 1848bd99e..63fc2f4c8 100644 --- a/src/infoplugins/generic/hypem/HypemPlugin.h +++ b/src/infoplugins/generic/hypem/HypemPlugin.h @@ -58,6 +58,7 @@ public slots: void chartTypes(); protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h index 17c57faf9..21043caeb 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h @@ -42,6 +42,7 @@ public: virtual ~MusicBrainzPlugin(); protected slots: + virtual void init() {} virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ); diff --git a/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h b/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h index 3f3557f8a..5c17c0c75 100644 --- a/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h +++ b/src/infoplugins/generic/musixmatch/MusixMatchPlugin.h @@ -46,6 +46,7 @@ public slots: void trackLyricsSlot(); protected slots: + virtual void init() {} virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp b/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp index 9d3c7cece..54910bf49 100644 --- a/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp +++ b/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp @@ -30,6 +30,16 @@ NewReleasesPlugin::NewReleasesPlugin() { m_nrVersion = "0"; m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease; +} + +NewReleasesPlugin::~NewReleasesPlugin() +{ + tDebug ( LOGVERBOSE ) << Q_FUNC_INFO; +} + +void +NewReleasesPlugin::init() +{ QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "NewReleasesPlugin", "nr_sources" ).toList(); foreach( const QVariant & source, source_qvarlist ) { m_nrSources.append( source.toString() ); @@ -41,11 +51,6 @@ NewReleasesPlugin::NewReleasesPlugin() fetchNRSourcesList( true ); } -NewReleasesPlugin::~NewReleasesPlugin() -{ - tDebug ( LOGVERBOSE ) << Q_FUNC_INFO; -} - void NewReleasesPlugin::dataError ( InfoRequestData requestData ) { emit info ( requestData, QVariant() ); diff --git a/src/infoplugins/generic/newreleases/NewReleasesPlugin.h b/src/infoplugins/generic/newreleases/NewReleasesPlugin.h index 3c355a577..85b24c31d 100644 --- a/src/infoplugins/generic/newreleases/NewReleasesPlugin.h +++ b/src/infoplugins/generic/newreleases/NewReleasesPlugin.h @@ -44,6 +44,7 @@ public: virtual ~NewReleasesPlugin(); protected slots: + virtual void init(); virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); diff --git a/src/infoplugins/generic/rovi/RoviPlugin.h b/src/infoplugins/generic/rovi/RoviPlugin.h index 5c782edb2..b54c3577a 100644 --- a/src/infoplugins/generic/rovi/RoviPlugin.h +++ b/src/infoplugins/generic/rovi/RoviPlugin.h @@ -43,6 +43,8 @@ public: virtual ~RoviPlugin(); protected: + virtual void init() {} + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/generic/spotify/SpotifyPlugin.h b/src/infoplugins/generic/spotify/SpotifyPlugin.h index e20e69aeb..c21600090 100644 --- a/src/infoplugins/generic/spotify/SpotifyPlugin.h +++ b/src/infoplugins/generic/spotify/SpotifyPlugin.h @@ -59,6 +59,7 @@ public slots: void chartTypes(); protected slots: + virtual void init() {} virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) diff --git a/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h b/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h index fc56e6267..fc672c00a 100644 --- a/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h +++ b/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.h @@ -39,6 +39,8 @@ public: virtual ~FdoNotifyPlugin(); protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( requestData ); diff --git a/src/infoplugins/linux/mpris/MprisPlugin.cpp b/src/infoplugins/linux/mpris/MprisPlugin.cpp index 02de7e158..8f8f6610b 100644 --- a/src/infoplugins/linux/mpris/MprisPlugin.cpp +++ b/src/infoplugins/linux/mpris/MprisPlugin.cpp @@ -54,7 +54,17 @@ MprisPlugin::MprisPlugin() // Types of pushInfo we care about m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; +} + +MprisPlugin::~MprisPlugin() +{ +} + + +void +MprisPlugin::init() +{ // DBus connection new MprisPluginRootAdaptor( this ); new MprisPluginPlayerAdaptor( this ); @@ -84,11 +94,6 @@ MprisPlugin::MprisPlugin() } -MprisPlugin::~MprisPlugin() -{ -} - - // org.mpris.MediaPlayer2 bool diff --git a/src/infoplugins/linux/mpris/MprisPlugin.h b/src/infoplugins/linux/mpris/MprisPlugin.h index 9e4d54e04..8a11fc1d4 100644 --- a/src/infoplugins/linux/mpris/MprisPlugin.h +++ b/src/infoplugins/linux/mpris/MprisPlugin.h @@ -142,6 +142,8 @@ public slots: void Stop(); protected slots: + virtual void init(); + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( requestData ); diff --git a/src/infoplugins/mac/adium/AdiumPlugin.h b/src/infoplugins/mac/adium/AdiumPlugin.h index a05b0863b..a4d3d50bf 100644 --- a/src/infoplugins/mac/adium/AdiumPlugin.h +++ b/src/infoplugins/mac/adium/AdiumPlugin.h @@ -44,6 +44,8 @@ public: virtual ~AdiumPlugin(); protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) { Q_UNUSED( requestData ); diff --git a/src/libtomahawk/infosystem/InfoSystem.h b/src/libtomahawk/infosystem/InfoSystem.h index 00a316718..324c1e352 100644 --- a/src/libtomahawk/infosystem/InfoSystem.h +++ b/src/libtomahawk/infosystem/InfoSystem.h @@ -101,6 +101,10 @@ class DLLEXPORT InfoPlugin : public QObject Q_OBJECT public: + /** + * @brief Creates the plugin. Do *not* perform any network-based setup tasks here; defer that to init(), which will be called automatically. + * + **/ InfoPlugin(); virtual ~InfoPlugin(); @@ -115,6 +119,14 @@ signals: void updateCache( Tomahawk::InfoSystem::InfoStringHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output ); protected slots: + + /** + * @brief Called after the plugin has been moved to the appropriate thread. Do network-based setup tasks here. + * + * @return void + **/ + virtual void init() = 0; + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) = 0; virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) = 0; virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) = 0; diff --git a/src/libtomahawk/infosystem/InfoSystemWorker.cpp b/src/libtomahawk/infosystem/InfoSystemWorker.cpp index f84b55bbd..f52ba8729 100644 --- a/src/libtomahawk/infosystem/InfoSystemWorker.cpp +++ b/src/libtomahawk/infosystem/InfoSystemWorker.cpp @@ -122,6 +122,8 @@ InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin ) SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ), Qt::QueuedConnection ); + + QMetaObject::invokeMethod( plugin.data(), "init", Qt::QueuedConnection ); } diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 5adba5422..e6596cfb3 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -464,7 +464,10 @@ nam() { QMutexLocker locker( &s_namAccessMutex ); if ( s_threadNamHash.contains( QThread::currentThread() ) ) + { + //tDebug() << Q_FUNC_INFO << "Found current thread in nam hash"; return s_threadNamHash[ QThread::currentThread() ]; + } if ( !s_threadNamHash.contains( TOMAHAWK_APPLICATION::instance()->thread() ) ) { @@ -476,6 +479,7 @@ nam() else return 0; } + tDebug() << Q_FUNC_INFO << "Found gui thread in nam hash"; // Create a nam for this thread based on the main thread's settings but with its own proxyfactory QNetworkAccessManager *mainNam = s_threadNamHash[ TOMAHAWK_APPLICATION::instance()->thread() ]; @@ -487,7 +491,9 @@ nam() s_threadNamHash[ QThread::currentThread() ] = newNam; - tDebug( LOGEXTRA ) << "created new nam for thread " << QThread::currentThread(); + tDebug( LOGEXTRA ) << Q_FUNC_INFO << "created new nam for thread " << QThread::currentThread(); + //QNetworkProxy proxy = dynamic_cast< TomahawkUtils::NetworkProxyFactory* >( newNam->proxyFactory() )->proxy(); + //tDebug() << Q_FUNC_INFO << "reply proxy properties: " << proxy.type() << proxy.hostName() << proxy.port(); return newNam; } @@ -524,6 +530,7 @@ setNam( QNetworkAccessManager* nam, bool noMutexLocker ) s_noProxyHostsMutex.unlock(); } + QNetworkProxyFactory::setApplicationProxyFactory( proxyFactory ); nam->setProxyFactory( proxyFactory ); s_threadNamHash[ QThread::currentThread() ] = nam; s_threadProxyFactoryHash[ QThread::currentThread() ] = proxyFactory; From d09145b06f5509c87057584bbdd2e1b102de7ad5 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 23 May 2012 13:27:25 -0400 Subject: [PATCH 038/433] Better debug output from whatshotwidget --- src/libtomahawk/widgets/WhatsHotWidget.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index 94068899a..c57f3601c 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -179,9 +179,15 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat if ( requestData.caller != s_whatsHotIdentifier ) return; + if ( output.isNull() ) + { + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Info came back empty"; + return; + } + if ( !output.canConvert< QVariantMap >() ) { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "WhatsHot: Could not parse output"; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "WhatsHot: Could not parse output into a map"; return; } From 76f463b81a152fd5dc2e5e1972513ceee3fcb599 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Wed, 23 May 2012 14:20:30 -0400 Subject: [PATCH 039/433] New logo --- .../icons/tomahawk-icon-128x128-grayscale.png | Bin 69076 -> 69076 bytes data/icons/tomahawk-icon-128x128.png | Bin 18676 -> 69076 bytes data/icons/tomahawk-icon-16x16.png | Bin 1362 -> 4346 bytes data/icons/tomahawk-icon-256x256.png | Bin 46412 -> 266130 bytes data/icons/tomahawk-icon-32x32.png | Bin 2627 -> 7434 bytes data/icons/tomahawk-icon-512x512.png | Bin 112854 -> 1054090 bytes data/icons/tomahawk-icon-64x64.png | Bin 7051 -> 19778 bytes 7 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/icons/tomahawk-icon-128x128-grayscale.png b/data/icons/tomahawk-icon-128x128-grayscale.png index 550781596b809f729dc32b47c6aa05611d60ba71..b3d67ccae284019dfa23c55fa8ed3a1a65c5756d 100644 GIT binary patch literal 69076 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�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 PM4ukVcVE(V_!a*TdI*lF diff --git a/data/icons/tomahawk-icon-128x128.png b/data/icons/tomahawk-icon-128x128.png index bbee6eb8044bb1affba590bd1338c0980e3b2aa9..ec05621dc798269ad605e4cbc9fc766fc5c31566 100644 GIT binary patch literal 69076 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 literal 18676 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 XGCD9Ys@u4*00000NkvXXu0mjfMnE)( diff --git a/data/icons/tomahawk-icon-16x16.png b/data/icons/tomahawk-icon-16x16.png index cd5709e6b8a4f0e4a6839746afdac187882bd6b3..8d2cd8589ae116d0df883b302b70cab623790012 100644 GIT binary patch literal 4346 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 literal 1362 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

tHH82n;0eA% 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%0D1t7DIq4NpjSCl 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 literal 46412 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

    ;WvL!P3qEdT}bZ{aeH%?5eNEvjT2A*;OpUBRG&n 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

    ;x{S5M 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 Q8dv~Qc&98=2{rouKXRD0LjV8( diff --git a/data/icons/tomahawk-icon-32x32.png b/data/icons/tomahawk-icon-32x32.png index 396e3f8fa8d2bd0a742a4c3a27f4e723a3914eb3..952151ba2609cc82bbfab2ba663f7836537cf571 100644 GIT binary patch literal 7434 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 Ef;oQF2><{9 diff --git a/data/icons/tomahawk-icon-512x512.png b/data/icons/tomahawk-icon-512x512.png index e42d30e85b785f36e812b4cbf41516ddeb87b1c2..b53561c6acdf8aec86df7cb9ef0d089c5b519ca5 100644 GIT binary patch literal 1054090 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

    (=sw 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 Date: Wed, 23 May 2012 14:43:38 -0400 Subject: [PATCH 040/433] Make black icon for use with OS X --- .../icons/tomahawk-icon-128x128-grayscale.png | Bin 69076 -> 69076 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/icons/tomahawk-icon-128x128-grayscale.png b/data/icons/tomahawk-icon-128x128-grayscale.png index b3d67ccae284019dfa23c55fa8ed3a1a65c5756d..bf97680d1bbd5665f878eda55771b743f4747037 100644 GIT binary patch literal 69076 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�kl;Vg|aRSR-JQN|(*BLOvo3JpsJ1~NaE~8To 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 Date: Wed, 23 May 2012 20:49:08 +0200 Subject: [PATCH 041/433] Make tray icon colorful on windows and linux again --- src/TomahawkTrayIcon.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/TomahawkTrayIcon.cpp b/src/TomahawkTrayIcon.cpp index 08abee130..6c4b40efe 100644 --- a/src/TomahawkTrayIcon.cpp +++ b/src/TomahawkTrayIcon.cpp @@ -41,7 +41,12 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) , m_showWindowAction( 0 ) , m_stopContinueAfterTrackAction( 0 ) { +#ifdef Q_WS_MAC QIcon icon( RESPATH "icons/tomahawk-icon-128x128-grayscale.png" ); +#else + QIcon icon( RESPATH "icons/tomahawk-icon-128x128.png" ); +#endif + setIcon( icon ); refreshToolTip(); From c685ba7c0335e4e6d88b32998368ead6bd9ac0b8 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Wed, 23 May 2012 14:50:06 -0400 Subject: [PATCH 042/433] Give black OS X systray icon a little more padding --- .../icons/tomahawk-icon-128x128-grayscale.png | Bin 69076 -> 69076 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/icons/tomahawk-icon-128x128-grayscale.png b/data/icons/tomahawk-icon-128x128-grayscale.png index bf97680d1bbd5665f878eda55771b743f4747037..f9daadb3321c75ce1cc106d2b3df34c552bba095 100644 GIT binary patch literal 69076 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 F|34Lxc6Vkk7tCtd*(v}3{r~*)Pu;x*y&vfs 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�kl;Vg|aRSR-JQN|(*BLOvo3JpsJ1~NaE~8To zj_lYoi)%MDEu&$26;ct8QNm(5MWQ+*MOsGg;LR*18G;c!bQzs$aAc=e3?YK1XC#~- z1Mk+KpM&lgBZARo2t!IP-2hYy&^(NURmkd!Ho{k4Ms;v5&uHYC^uvsOml3}5GLlvq zu}E}qK+Z$&Gfhi#81Pf$DZM1eeBi=p8<0;uKFI-q}y2K9@Nwp>^USmKnUwM9wY?QN6Tj_GTx}IHD zWpRaxb4*=CFhqHNX#L_&p0WhmW977YJre{BM#_pqy9QKpV&fHc%!~yL3g(2$^FkE> z?xOJ=Q+4apT{$nNfzrrsBFqvP48e<#U0LDQO4dAFV~suG4Q{FKnXSnf1l3Zkc(jx! z%yrHbw9s{zM^#{h33$?hCNu zF;bo&f-!>2h}jjV5xR64S84{Ic+Ct%_B22vVU{VDh(Ufgf`dmHf&(j9%`>v{kju&A znFSM{*+5}&of@=Fl!?zTQag>h54LDv!=8oHz6Z#gZ*H&GqS&R$PeCsRGx8HuGDWlU z$uB8;3^OJc0@(elx=R+(STOM{OJtx1U97ZObfQ+436ol1r^YN_yu!)(e0d6S1W_*a zWmKOM1rJ!ok5U-M#cTlhtH<0{sSHbDenBt;?cYyA@ppr2*!~$7}%9`-BChgd)BS8eld62Hr(QSvA0+ z_XYpW;zrE!|16kT)oNyWpVL>72Qag`&7}QvjP<#^vjBWJ?VH_xPLW0M(Pg2fQe*&y zw(9bI;?F*x0DPn_4Z+~BEX!;Fh4I*}A!YkuA?j1FhS4z_0Nb?E zFz%v)paDC(3t%r(8`0%yDhj&?V`I@dIJWN)kN5dNPvf|NOp1^{4u&9=$ z1XV9xd446Dy5r!-gPfO~zTRh%4pSEZOg$-1Vx%#kR}hx`1d@k}7h$vTA$k%Cak_KE z!;O%S2&P3I0#)ZHPqff=m&cHLhF6?;SHoEVcYL*^;Z~gYxo<56)bbb-(oG>XKD^=y zYmFX&hRMpGro|L?VrRhvze#7c;B_VO<1{RQ0Eihg0~SnbW#N|=)Y5!D9(yk`h$A0U zW<`sC_s)WAj@xTLco5CQm{`S9D-VhzKeHibz)BQ@h3U?|l<$-l?<_u`zbwe&PQ_#y-c=O+<5HTCYC6*KE=(=E~gf=k5m# zwG#8Cd{{89x>Ria5J`OtMzmO#JNdMj!CgZ=e5JZl6iiCx63~N7DX%UNjyjRnER^W! zjf2G>snG)%=>g`%*wVPI2>@}&cUMTmghw+je0U>oGpCTw>)q%D?@sbws}Ka2I+hFo zP&j|v6oNcz4XhJ?TY}sm$nyex4vhG8+QV1zPF3ZdyyKxnqAxwV((7K-^26eb-sM*{ zT9P7QU_=d$cp8^GTJCUZNpnYAN`nD3?mETBsfDhVJg!qeiJL4yt(0jYswEHMV4#0i zq79W^kju?VnDoTSw5|Lo)0H0jYIzAG%`-D`-aIaPsm-pH;o3=w@7j;awu9qIrx3fHnXp>+mpWb9ce3PgEsKeLcj%gPuOj9Uosz z1Mds7rr}4{>_f#Z zbgCqio;X$BqRh?=dT4setIAVPf+r?=(s^tg>A}u3uO2y-@~UE?2DeJ(jK-<*)09A2 zrBMKC<%rv(yo@G1K9EUG9X?^sWDN!rYiY zNWgL5;4})i0(d!*Rc>0}thAIwmtJ|Jj7%vXmpBl>j6VX-M`sAE@`7xvG}OwguKW>& zs{Et53lPgw(-zvA#bh3L5D>qxc@n0IexgU9=E*#G6ci02n+eQGT^Okl-3EZ)sMXxR zFbGPl9B)q^DwFf?<fFv?JHn28}M zv-efckPoe|5AJ-@1IV=qh5#G3DlMp>y+b}7ij}T{S1w+`KFc<43Kon9?xJGh90DAU z0N1Ke#BA^2!V+V$VmuZRo0d17zHV{qMNH&n>bn4hrZ5N1E@*2;^{($2&?Tab4G<-D Mek5UAr;&6256Cg| Date: Wed, 23 May 2012 15:01:53 -0400 Subject: [PATCH 043/433] Add logo SVG --- data/icons/tomahawk-icon.svg | 313 ++--------------------------------- 1 file changed, 15 insertions(+), 298 deletions(-) diff --git a/data/icons/tomahawk-icon.svg b/data/icons/tomahawk-icon.svg index 49f1a86b5..c36bc26f2 100644 --- a/data/icons/tomahawk-icon.svg +++ b/data/icons/tomahawk-icon.svg @@ -1,304 +1,21 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + width="841.89px" height="595.28px" viewBox="0 0 841.89 595.28" enable-background="new 0 0 841.89 595.28" xml:space="preserve"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 1dd053dc0f0e7d57dd4a4d4cbf2705fc4e59ec3d Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 23 May 2012 17:30:54 -0400 Subject: [PATCH 044/433] Emit a failed signal if there's no internet, so things that depend on AtticaManager move forward --- src/libtomahawk/AtticaManager.cpp | 26 +++++++++++++++++++++++++- src/libtomahawk/AtticaManager.h | 7 +++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index c6f2d95f4..450676e27 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -35,6 +35,7 @@ #include "accounts/ResolverAccount.h" #include "accounts/AccountManager.h" #include "utils/BinaryInstallerHelper.h" +#include "utils/Closure.h" using namespace Attica; @@ -48,7 +49,11 @@ AtticaManager::AtticaManager( QObject* parent ) connect( &m_manager, SIGNAL( providerAdded( Attica::Provider ) ), this, SLOT( providerAdded( Attica::Provider ) ) ); // resolvers - m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ); +// m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ); + QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ) ); + NewClosure( reply, SIGNAL( finished() ), this, SLOT( providerFetched( QNetworkReply* ) ), reply ); + connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( providerError( QNetworkReply::NetworkError ) ) ); + // m_manager.addProviderFile( QUrl( "http://lycophron/resolvers/providers.xml" ) ); qRegisterMetaType< Attica::Content >( "Attica::Content" ); @@ -243,6 +248,25 @@ AtticaManager::resolverData(const QString &atticaId) const } +void +AtticaManager::providerError( QNetworkReply::NetworkError err ) +{ + // So those who care know + emit resolversLoaded( Content::List() ); +} + + +void +AtticaManager::providerFetched( QNetworkReply* reply ) +{ + Q_ASSERT( reply ); + if ( !reply ) + return; + + m_manager.addProviderFromXml( reply->readAll() ); +} + + void AtticaManager::providerAdded( const Provider& provider ) { diff --git a/src/libtomahawk/AtticaManager.h b/src/libtomahawk/AtticaManager.h index b6b206069..bca1d7440 100644 --- a/src/libtomahawk/AtticaManager.h +++ b/src/libtomahawk/AtticaManager.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "DllMacro.h" #include "accounts/Account.h" @@ -124,7 +125,10 @@ signals: void resolverInstallationFailed( const QString& resolverId ); void startedInstalling( const QString& resolverId ); + private slots: + void providerFetched( QNetworkReply* reply ); + void providerError( QNetworkReply::NetworkError ); void providerAdded( const Attica::Provider& ); void categoriesReturned( Attica::BaseJob* ); void resolversList( Attica::BaseJob* ); @@ -139,7 +143,6 @@ private slots: void syncServerData(); private: - QString extractPayload( const QString& filename, const QString& resolverId ) const; void doResolverRemove( const QString& id ) const; void doInstallResolver( const Attica::Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler ); @@ -171,5 +174,5 @@ protected: }; Q_DECLARE_METATYPE( Attica::Content ); - +Q_DECLARE_METATYPE( QNetworkReply* ); #endif // ATTICAMANAGER_H From 8aec11c0e9699e0502d10e9296354608b32e12c2 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Wed, 23 May 2012 22:16:59 +0000 Subject: [PATCH 045/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 721 +++++++++++++++++++++-------------------- lang/tomahawk_bg.ts | 120 +++---- lang/tomahawk_ca.ts | 120 +++---- lang/tomahawk_de.ts | 120 +++---- lang/tomahawk_en.ts | 120 +++---- lang/tomahawk_es.ts | 120 +++---- lang/tomahawk_fr.ts | 256 +++++++-------- lang/tomahawk_ja.ts | 120 +++---- lang/tomahawk_pl.ts | 120 +++---- lang/tomahawk_pt_BR.ts | 120 +++---- lang/tomahawk_ru.ts | 120 +++---- lang/tomahawk_sv.ts | 120 +++---- lang/tomahawk_tr.ts | 120 +++---- lang/tomahawk_zh_CN.ts | 120 +++---- lang/tomahawk_zh_TW.ts | 120 +++---- 15 files changed, 1273 insertions(+), 1264 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index c794d760a..df32880ca 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -40,14 +40,15 @@ Error displaying ACL info - + خطأ في عرض معلومات ACL Allow %1 to connect and stream from you? - + هل تسمح ل %1 +بالربط بك ومشاركة أغانيك ؟ @@ -55,7 +56,7 @@ connect and stream from you? &Listen Along - ظاهرة + &تابع الاستماع @@ -160,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. بعد إجراء مسح مجموعة أغانيك الخاصة ستجد ألبوماتك المضافة هنا. - + This collection doesn't have any recent albums. هذه المجموعة لا تحتوي على ألبومات جديدة. @@ -221,7 +222,7 @@ connect and stream from you? Play - إستماع + إستمع @@ -236,7 +237,7 @@ connect and stream from you? Artist - الفنان + فنان @@ -251,7 +252,7 @@ connect and stream from you? social - + اجتماعي @@ -295,7 +296,7 @@ connect and stream from you? New Playlist - خلق قائمة أغاني جديدة + إنشاء قائمة أغاني جديدة @@ -303,7 +304,7 @@ connect and stream from you? New Station - خلق إذاعة جديدة + إنشاء إذاعة جديدة @@ -389,12 +390,12 @@ connect and stream from you? Send this report - + أرسل هذا التقرير Don't send - + لا ترسل @@ -409,7 +410,7 @@ connect and stream from you? Uploaded %L1 of %L2 KB. - + تحميل %L1 من أصل %L2 كب @@ -441,7 +442,7 @@ connect and stream from you? About - + عن @@ -557,7 +558,7 @@ connect and stream from you? Import Playback History - + استيراد تاريخ إعادة الإستماع @@ -640,7 +641,7 @@ connect and stream from you? Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! - توماهوك يقدم مجموعة متنوعة من الطرق اللتي تساعدك على خلق قوائم أغاني و إيجاد الموسيقى اللتي تستمتع إليها! + توماهوك يقدم مجموعة متنوعة من الطرق اللتي تساعدك على إنشاء قوائم أغاني و إيجاد الموسيقى اللتي تستمتع إليها! @@ -650,12 +651,12 @@ connect and stream from you? &Create Playlist - &خلق قائمة أغاني + &إنشاء قائمة أغاني Create a new playlist - خلق قائمة أغاني جديدة + إنشاء قائمة أغاني جديدة @@ -663,7 +664,7 @@ connect and stream from you? New Releases - + جديد الاصدارات @@ -671,12 +672,12 @@ connect and stream from you? Artist - + فنان Title - + عنوان @@ -686,22 +687,22 @@ connect and stream from you? Album - + البوم Track - + اغنية Duration - + مدة Bitrate - + معدل البت @@ -711,22 +712,22 @@ connect and stream from you? Year - + سنة Size - + حجم Origin - + أصل Score - + علامة @@ -813,12 +814,12 @@ connect and stream from you? Create Manual Playlist - خلق قائمة أغاني جديدة يدويا + إنشاء قائمة أغاني جديدة يدويا Create Automatic Playlist - خلق قائمة أغاني جديدة تلقائيا + إنشاء قائمة أغاني جديدة تلقائيا @@ -887,73 +888,73 @@ connect and stream from you? Use proxy for DNS lookups? - + استخدام ألوكيل لعمليات البحث عن ألدي أن أس (DNS ) ؟ QObject - + %n year(s) ago منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - + %n year(s) - - - - - %n month(s) ago - + منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - %n month(s) - + %n month(s) ago + منذ %n شهرمنذ شهر %nمنذ شهرين %nمنذ %n أشهرمنذ %n أشهرمنذ %n أشهر - - %n week(s) ago - + + %n month(s) + منذ %n شهرمنذ شهر %nمنذ شهرين %nمنذ %n أشهرمنذ %n أشهرمنذ %n أشهر - %n week(s) - + %n week(s) ago + منذ %n أسبوعمنذ أسبوع %nمنذ أسبوعين %nمنذ %n أسابيعمنذ %n أسابيعمنذ %n أسابيع - - %n day(s) ago - + + %n week(s) + منذ %n أسبوعمنذ أسبوع %nمنذ أسبوعين %nمنذ %n أسابيعمنذ %n أسابيعمنذ %n أسابيع - %n day(s) - + %n day(s) ago + منذ %n يوممنذ يوم %nمنذ يومين %nمنذ %n أياممنذ %n أياممنذ %n أيام - - %n hour(s) ago - + + %n day(s) + منذ %n يوممنذ يوم %nمنذ يومين %nمنذ %n أياممنذ %n أياممنذ %n أيام + %n hour(s) ago + منذ %n ساعةمنذ ساعة %nمنذ ساعتين %nمنذ %n ساعاتمنذ %n ساعاتمنذ %n ساعات + + + %n hour(s) - + منذ %n ساعةمنذ ساعة %nمنذ ساعتين %nمنذ %n ساعاتمنذ %n ساعاتمنذ %n ساعات - + %1 minutes ago منذ %1 دقائق - + %1 minutes %1 دقائق - + just now الآن @@ -970,7 +971,7 @@ connect and stream from you? Status Updaters - + أنظمة تحديث حالتك @@ -978,7 +979,7 @@ connect and stream from you? ZIP/UNZIP API error %1 - + مشكلة %1 في "ZIP/UNZIP API" @@ -1013,12 +1014,12 @@ connect and stream from you? Not found: %1 - + لم يوجد: %1 Failed to load: %1 - + فشل في تحميل: %1 @@ -1039,7 +1040,7 @@ connect and stream from you? Results for '%1' - + نتائج البحث عن '%1' @@ -1062,7 +1063,7 @@ connect and stream from you? Some changed settings will not take effect until Tomahawk is restarted - + بعض الإعدادات التي تم تغييرها لن تصبح نافذة المفعول حتى يتم إعادة تشغيل توماهوك @@ -1072,7 +1073,7 @@ connect and stream from you? Install resolver from file - + تثبيت محلل من ملف @@ -1090,12 +1091,12 @@ connect and stream from you? Most Played Playlists - + قوائم الأغاني التي سمعت كثيرا Most Played Tracks You Don't Have - + الأغاني التي سمعت كثيرا و التي ليست موجودة لديك @@ -1108,7 +1109,7 @@ connect and stream from you? Facebook - + فيسبوك (Facebook) @@ -1118,7 +1119,7 @@ connect and stream from you? Cover - + غطاء @@ -1128,7 +1129,7 @@ connect and stream from you? Listening to "%1" by %2 and loving it! %3 - + الإستماع إلى "%1" ل%2 ومحبتها! %3 @@ -1138,7 +1139,7 @@ connect and stream from you? %1 characters left - + تبقى %1 حروف @@ -1156,7 +1157,7 @@ connect and stream from you? Artist - الفنان + فنان @@ -1166,7 +1167,7 @@ connect and stream from you? Top 10 - + توب ١٠ @@ -1206,7 +1207,7 @@ connect and stream from you? Latest Additions - + الإضافة الأخيرة @@ -1216,17 +1217,17 @@ connect and stream from you? New Additions - + الإضافة الجديدة My recent activity - + نشاطاتي الأخيرة Recent activity from %1 - + النشاطات المؤخرة ل %1 @@ -1245,7 +1246,7 @@ connect and stream from you? Recently Played - + تم الاستماع لها مؤخرا @@ -1255,17 +1256,17 @@ connect and stream from you? SuperCollection - + سوبر كولكشن Latest additions to your collection - + آخر إضافات على مجموعتك Latest additions to %1's collection - + آخر إضافات على مجموعة %1 @@ -1275,12 +1276,12 @@ connect and stream from you? Your recently played tracks - + الأغاني التي إستمعت إليها مؤخرا %1's recently played tracks - + الأغاني التي سمعها مؤخرا %1 @@ -1293,12 +1294,12 @@ connect and stream from you? &Delete %1 - + &أحذف %1 &Export Playlist - + &تصدير قائمة الأغاني @@ -1308,7 +1309,7 @@ connect and stream from you? Playlists (*.xspf) - + قوائم أغاني (*.xspf) @@ -1331,7 +1332,7 @@ connect and stream from you? Automatic Playlist - + قائمة أغاني أوتوماتيكية @@ -1351,12 +1352,12 @@ connect and stream from you? My Music - + موسيقتي الخاصة SuperCollection - + سوبر كولكشن @@ -1366,12 +1367,12 @@ connect and stream from you? Dashboard - + لوحة القيادة Recently Played - تم الإستماع مؤخرا + تم الاستماع لها مؤخرا @@ -1381,7 +1382,7 @@ connect and stream from you? New Releases - + جديد الاصدارات @@ -1409,12 +1410,12 @@ connect and stream from you? Log In - + تسجيل الدخول Right click on any Tomahawk playlist to sync it to Spotify. - + أنقر يمينا على أية قائمة أغاني في توماهوك للمزامنة مع سبوتيفي (Spotify). @@ -1424,12 +1425,12 @@ connect and stream from you? Spotify playlists to keep in sync: - + قوائم أغاني سبوتيفي (Spotify) التي يجب إبقائها بتزامن: Delete Tomahawk playlist when removing synchronization - + حذف قوائم أغاني توماهوك عند إزالة التزام @@ -1447,12 +1448,12 @@ connect and stream from you? Delete in Spotify? - + أحذف في سبوتيفي (Spotify)؟ Would you like to delete the corresponding Spotify playlist as well? - + هل ترغب في حذف قائمة التشغيل المطابقة على سبوتيفي (Spotify)؟ @@ -1478,7 +1479,9 @@ connect and stream from you? and using it to craft personalized radios. Enabling this option will allow you (and all your friends) to create automatic playlists and stations based on your personal taste profile. - + "The Echo Nest" يدعم إبقاء مسار فوقية فهرسك واستخدامه + لصياغة إذاعات شخصية. تمكين هذا الخيار يسمح لك (و لأصدقائك) +إنشاء قوائم أغاني أوتوماتيكيا و إذاعات حسب ذوقك الشخصي. @@ -1493,22 +1496,22 @@ connect and stream from you? Time between scans, in seconds: - + الوقت بين المسوحات، بالثواني: Advanced Settings - + إعدادات متقدمة Remote Peer Connection Method - + طريقة الاتصال بالند البعيد None (outgoing connections only) - + لا شيء (الاتصالات الصادرة فقط) @@ -1568,7 +1571,7 @@ connect and stream from you? Other Settings - + إعدادات أخرى @@ -1578,7 +1581,7 @@ connect and stream from you? Allow web browsers to interact with Tomahawk (recommended) - + السماح لمحرك البحث بالتفاعل مع توماهوك (موصى به) @@ -1596,7 +1599,7 @@ connect and stream from you? %1 downloads - + تحميل %1 @@ -1606,7 +1609,7 @@ connect and stream from you? Connecting... - + يجرى الاتصال... @@ -1617,14 +1620,14 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + مطلوب تثبيت يدوي - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على لنكس. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1637,7 +1640,7 @@ connect and stream from you? Google Address - + الحساب الخاص بجوجل (Google) @@ -1655,7 +1658,7 @@ connect and stream from you? Connect to Google Talk to find your friends - + تواصل مع جوجل توك (Google Talk) لإيجاد أصدقائك @@ -1663,12 +1666,12 @@ connect and stream from you? Add Friend - + أضف صديق Enter Google Address: - + أدخل الحساب الخاص بجوجل (Google): @@ -1676,7 +1679,7 @@ connect and stream from you? Scrobble your tracks to last.fm, and find freely downloadable tracks to play - + إبعث أغانيك الخاصة إلى last .fm و جد أغاني جديدة مجانا للاستماع إليها @@ -1684,7 +1687,7 @@ connect and stream from you? Testing... - + اختبار... @@ -1695,22 +1698,22 @@ connect and stream from you? Importing %1 e.g. Importing 2012/01/01 - + استيراد %1 Importing History... - + نقل التاريخ... History Incomplete. Resume - + تاريخ ناقص. استأنف Playback History Imported - + تم استيراد تاريخ إعادة الإستماع @@ -1732,14 +1735,14 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify - + أوقف المزامنة مع سبوتيفي (Spotify) @@ -1747,22 +1750,22 @@ connect and stream from you? Logging in... - + جاري تسجيل الدخول... Logged in! - + مسجل! Failed: %1 - + فشل: %1 Log In - + تسجيل الدخول @@ -1770,7 +1773,7 @@ connect and stream from you? Play music from and sync your playlists with Spotify Premium - + إسمع موسيقى و زامن قوائم تشغيلك مع سبوتيفي بريميوم (Spotify Premium) @@ -1788,13 +1791,13 @@ connect and stream from you? Tweet! - + تويت (Tweet)! Status: No saved credentials - + الحالة: بيانات غير محفوظة @@ -1807,13 +1810,13 @@ connect and stream from you? Status: Credentials saved for %1 - + الحالة: بيانات %1 حفظت De-authenticate - + قطع المصادقة @@ -1830,22 +1833,23 @@ connect and stream from you? The credentials could not be verified. You may wish to try re-authenticating. - + لم نستطيع التحقق من صحة البيانات. +قد ترغب بإعادة المصادقة. Status: Error validating credentials - + الحالة: خطأ في التحقق من صحة البيانات Global Tweet - + تويت شامل (Global Tweet) Direct Message - + رسالة مباشرة @@ -1855,12 +1859,12 @@ You may wish to try re-authenticating. @Mention - + @ذكر Send Mention! - + إرسال ذكر! @@ -1901,7 +1905,7 @@ You may wish to try re-authenticating. There was an error posting your direct message -- sorry! - + نعتذر، حصل خطأ في نشر رسالتك المباشرة ! @@ -1914,7 +1918,7 @@ You may wish to try re-authenticating. Log on to your Jabber/XMPP account to connect to your friends - + أدخل إلى حسابك على Jabber/XMPP للربط بأصدقائك. @@ -1922,7 +1926,7 @@ You may wish to try re-authenticating. Automatically connect to Tomahawks on the local network - أربط نفسك بيتوماهاوك على الشبكة المحلية بطريقة مباشرة + أربط نفسك بتوماهاوك على الشبكة المحلية بطريقة مباشرة @@ -1930,14 +1934,14 @@ You may wish to try re-authenticating. &Play - + &إستمع Add to &Queue - + أضف إلى &قائمة الانتظار @@ -1958,17 +1962,17 @@ You may wish to try re-authenticating. &Delete Items - + &أحذف البنود &Continue Playback after this Track - + &أكمل الاستماع بعد هذه الأغنية &Stop Playback after this Track - + &أوقف الاستماع بعد هذه الأغنية @@ -1978,7 +1982,7 @@ You may wish to try re-authenticating. &Delete Item - + &أحذف البند @@ -2029,12 +2033,12 @@ You may wish to try re-authenticating. Fetching %1 from database - + جلب %1 من قاعدة البيانات Parsing %1 %2 - + تحليل %1 %2 @@ -2042,7 +2046,7 @@ You may wish to try re-authenticating. Click to collapse - + إضغط للتقليص @@ -2053,12 +2057,14 @@ You may wish to try re-authenticating. Could not find a playable track. Please change the filters or try again. - + لم يوجد أغنية للاستماع إليها. + +غير كلمة الترشيح وأعد الكرة. Failed to generate preview with the desired filters - + فشل في إيجاد عرض مسبق للبحث المطلوب @@ -2066,12 +2072,12 @@ Please change the filters or try again. Type: - + نوع: Generate - + توليد @@ -2079,17 +2085,17 @@ Please change the filters or try again. Add some filters above to seed this station! - + أدخل بعض الترشيحات أعلاه لتوزيع هذه الإذاعة! Press Generate to get started! - + إضغط "توليد" لتبدأ! Add some filters above, and press Generate to get started! - + أدخل بعض الترشيحات أعلاه ثم iضغط "توليد" لتبدأ! @@ -2099,7 +2105,9 @@ Please change the filters or try again. Station ran out of tracks! Try tweaking the filters for a new set of songs to play. - + الإذاعة فرغت من الأغاني! + +عدل في كلمة الترشيح لإيجاد مجموعة جديدة من الأغاني. @@ -2128,7 +2136,7 @@ Try tweaking the filters for a new set of songs to play. similar to - + مشابهة ل @@ -2139,7 +2147,7 @@ Try tweaking the filters for a new set of songs to play. Less - + أقل @@ -2150,7 +2158,7 @@ Try tweaking the filters for a new set of songs to play. More - + أكثر @@ -2185,12 +2193,12 @@ Try tweaking the filters for a new set of songs to play. Major - + رئيسي Minor - + ثانوي @@ -2255,27 +2263,27 @@ Try tweaking the filters for a new set of songs to play. Ascending - + تصاعدي Descending - + تنازلي Tempo - + سرعة إيقاع Duration - + مدة Loudness - + قوة الصوت @@ -2290,68 +2298,68 @@ Try tweaking the filters for a new set of songs to play. Song Hotttnesss - + شعبية الأغنية Latitude - + مدى Longitude - + طول Mode - + أسلوب Key - + مفتاح Energy - + حيوية Danceability - + القابلية للرقص only by ~%1 - + فقط من جانب ~%1 similar to ~%1 - + مشابهة ل%1 with genre ~%1 - + مع النوع ~%1 from no one - + من لا أحد My Collection - + مجموعتي الخاصة from %1 radio - + من إذاعة %1 @@ -2391,7 +2399,7 @@ Try tweaking the filters for a new set of songs to play. sorted in %1 %2 order - + تم فرزها بالترتيب %1 %2 @@ -2414,7 +2422,7 @@ Try tweaking the filters for a new set of songs to play. Much less - + أقل بكثير @@ -2424,52 +2432,52 @@ Try tweaking the filters for a new set of songs to play. A bit less - + أقل بقليل Keep at current - + أبقه على حاله A bit more - + أكثر قليلا More - + أكثر Much more - + أكثر من ذلك بكثير Tempo - + سرعة إيقاع Loudness - + قوة الصوت Danceability - + درجة الرقص Energy - + حيوية Song Hotttnesss - + شعبية الأغنية @@ -2484,12 +2492,12 @@ Try tweaking the filters for a new set of songs to play. By Description - + من خلال الوصف Enter a description - + أدخل الوصف @@ -2513,22 +2521,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + الأكثر شهرة بالإجمال - + Artists - الفنانين + فنانين - + Albums ألبومات - + Tracks أغاني @@ -2566,7 +2574,7 @@ Try tweaking the filters for a new set of songs to play. Top Artists - أهم الفنانين + أفضل الفنانين @@ -2577,7 +2585,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums ألبومات @@ -2603,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. New Playlist - + قائمة أغاني جديدة @@ -2613,17 +2621,17 @@ Try tweaking the filters for a new set of songs to play. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + بعض الأغاني في قائمة التشغيل لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. XSPF Error - + خطأ XSPF This is not a valid XSPF playlist. - + قائمة الأغاني XSPF هذه ليست صالحة. @@ -2637,7 +2645,7 @@ Try tweaking the filters for a new set of songs to play. &Listen Along - + تابع الاستماع @@ -2697,35 +2705,35 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + يجري مسح (%L1 أغنية) - + Scanning - + مسح - + Checking - + فحص - + Fetching - + جلب - + Parsing - + تحليل - + Saving (%1%) - + تحفيظ(%1%) @@ -2741,7 +2749,7 @@ Try tweaking the filters for a new set of songs to play. Automatically update from XSPF - + تحديث تلقائي من XSPF @@ -2749,7 +2757,7 @@ Try tweaking the filters for a new set of songs to play. My Collection - + مجموعتي الخاصة @@ -2763,46 +2771,47 @@ Try tweaking the filters for a new set of songs to play. After authenticating on Twitter's web site, enter the displayed PIN number here: - + بعد المصادقة على موقع تويتر (twitter)، +أدخل رقم البين (PIN) الموجود أمامك على الشاشة هنا: TomahawkTrayIcon - + &Stop Playback after current Track - + &أوقف الاستماع بعد الأغنية الحالية - - + + Hide Tomahawk Window إخفي نافذة توماهوك - + Show Tomahawk Window أظهر نافذة توماهوك - + Currently not playing. - + لا يتم الاستماع حاليا. - + Play - + إستمع - + Pause - + &Continue Playback after current Track - + &أكمل الاستماع بعد الأغنية الحالية @@ -2815,32 +2824,32 @@ enter the displayed PIN number here: &Settings - + إعدادات &Controls - + &ضوابط &Network - + &شبكة &Window - + &نافذة &Help - + &مساعدة &Quit - + &إنهاء @@ -2855,17 +2864,17 @@ enter the displayed PIN number here: Add &Friend... - + أضف &صديق... U&pdate Collection - + &تحديث المجموعة Update Collection - + تحديث المجموعة @@ -2880,7 +2889,7 @@ enter the displayed PIN number here: Create &New Playlist... - + إنشاء &قائمة أغاني جديدة @@ -2890,12 +2899,12 @@ enter the displayed PIN number here: Create New &Automatic Playlist - + إنشاء &قائمة أغاني جديدة أوتوماتيكيا Create New &Station - + إنشاء &قائمة أغاني جديدة @@ -2910,17 +2919,17 @@ enter the displayed PIN number here: Minimize - + خفض Ctrl+M - + Ctrl+M Zoom - + زوم @@ -2935,81 +2944,81 @@ enter the displayed PIN number here: Fully &Rescan Collection - + إعادة &مسح المجموعة كاملة Fully Rescan Collection - + إعادة مسح المجموعة كاملة Play - + إستمع Space - + مساحة Previous - + سابق Next - + التالي Back - + إلى الوراء Go back one page - + العودة صفحة واحدة إلى الوراء Forward - + تقدم Go forward one page - + تقدم صفحة واحدة Global Search... - + بحث شامل... Check For Updates... - + التحقق من التحديثات... Connect To Peer - + ربط بالند Enter peer address: - + أدخل عنوان الصديق: Enter peer port: - + أدخل بوابة الصديق: @@ -3024,7 +3033,7 @@ enter the displayed PIN number here: This is not a valid XSPF playlist. - + قائمة الأغاني XSPF هذه ليست صالحة. @@ -3034,37 +3043,37 @@ enter the displayed PIN number here: Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. Create New Station - + إنشاء &قائمة أغاني جديدة Name: - + الاسم: New Station - + إذاعة جديدة New Playlist - + قائمة أغاني جديدة @@ -3084,12 +3093,12 @@ enter the displayed PIN number here: Authentication Error - + خطأ في المصادقة Error connecting to SIP: Authentication failed! - + خطأ في الاتصال بسيب (SIP): فشلت المصادقة! @@ -3159,7 +3168,7 @@ enter the displayed PIN number here: Artists - الفنانين + فنانين @@ -3179,7 +3188,7 @@ enter the displayed PIN number here: Sources - + المصادر @@ -3192,7 +3201,7 @@ enter the displayed PIN number here: Top Hits - + الأكثر شهرة @@ -3220,7 +3229,7 @@ enter the displayed PIN number here: Artist - الفنان + فنان @@ -3235,12 +3244,12 @@ enter the displayed PIN number here: Statistics - + إحصائيات Lyrics - + كلمات @@ -3250,7 +3259,7 @@ enter the displayed PIN number here: You've listened to this track %n time(s). - + لقد استمعت إلى هذه الأغنية %n مرةلقد استمعت إلى هذه الأغنية مرة %nلقد استمعت إلى هذه الأغنية مرتين %nلقد استمعت إلى هذه الأغنية %n مراتلقد استمعت إلى هذه الأغنية %n مراتلقد استمعت إلى هذه الأغنية %n مرات @@ -3260,7 +3269,7 @@ enter the displayed PIN number here: You first listened to it on %1. - + استمعت إليها أولاً في %1 @@ -3278,7 +3287,7 @@ enter the displayed PIN number here: Sorry, your filter '%1' did not match any results. - + عذراً، ترشيحك "%1" لم يطابق أي نتائج. @@ -3286,12 +3295,12 @@ enter the displayed PIN number here: from - + من to - + إلى @@ -3299,7 +3308,7 @@ enter the displayed PIN number here: Unknown - + مجهول @@ -3307,42 +3316,42 @@ enter the displayed PIN number here: Name - + اسم Duration - + مدة Bitrate - + معدل البت Age - + عمر Year - + سنة Size - + حجم Origin - + أصل Composer - + مؤلف @@ -3353,13 +3362,13 @@ enter the displayed PIN number here: My Collection - + مجموعتي الخاصة Collection of %1 - + مجموعة %1 @@ -3372,7 +3381,7 @@ enter the displayed PIN number here: The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - + مساعد تويتر يسمح لك بإكتشاف والإستماع إلى الموسيقى من أصدقائك على تويتر المستخدمين لتوماهوك بالإضافة إلى نشر الرسائل إلى حسابك. @@ -3387,7 +3396,7 @@ enter the displayed PIN number here: Twitter Connections - + إتصالات بتويتر (Twitter) @@ -3407,7 +3416,7 @@ You can re-send a sync message at any time simply by sending another tweet using Global Tweet - + تويت شامل (Global Tweet) @@ -3435,7 +3444,7 @@ You can re-send a sync message at any time simply by sending another tweet using SuperCollection - + سوبر كولكشن @@ -3463,12 +3472,12 @@ You can re-send a sync message at any time simply by sending another tweet using Recent Additions - + آخر الإضافات Newest Stations & Playlists - + أجدد الإذاعات و قوائم الأغاني @@ -3478,7 +3487,7 @@ You can re-send a sync message at any time simply by sending another tweet using No recently created playlists in your network. - + لا قوائم أغاني جديدة أنشئت مؤخرا على شبكتك. @@ -3545,22 +3554,22 @@ Lyrics for "%1" by %2: Failed to parse contents of XSPF playlist - + فشل في تحليل محتويات قائمة الأغاني XSPF Some playlist entries were found without artist and track name, they will be omitted - + تم العثور على مداخل في قوائم الأغاني لا تحتوي على إسم فنان أو إسم أغنية، هذه المداخل سوف تحذف. Failed to fetch the desired playlist from the network, or the desired file does not exist - + فشل في جلب قائمة الأغاني المطلوبة من الشبكة، أو الملف المطلوب غير موجود New Playlist - + قائمة أغاني جديدة @@ -3579,12 +3588,12 @@ Lyrics for "%1" by %2: Save log - + حفظ تسجيل الدخول Disabled - + تعطيل @@ -3624,12 +3633,12 @@ Lyrics for "%1" by %2: Custom - + تعديل Close - + أغلق @@ -3692,7 +3701,7 @@ Lyrics for "%1" by %2: Server: - + خادم" @@ -3702,125 +3711,125 @@ Lyrics for "%1" by %2: Lots of servers don't support this (e.g. GTalk, jabber.org) - + الكثير من الخوادم لا تدعم هذا (e.g. GTalk, jabber.org) Publish currently playing track - + أنشر الأغنية التي تسمع الآن Enforce secure connection - + أفرض إتصال أمن XmppSipPlugin - + User Interaction تفاعل المستخدم - + Host is unknown - + المضيف مجهول - + Item not found - + البند غير موجودة - + Authorization Error - + خطا في الترخيص - + Remote Stream Error - + Remote Connection failed - + فشل في الاتصال البعيد - + Internal Server Error - + خطأ داخلي في الخادم - + System shutdown - + Conflict - + تضارب - + Unknown - + No Compression Support - + لا دعم للضغط - + No Encryption Support - + لا دعم للتشفير - + No Authorization Support - + لا دعم للترخيص - + No Supported Feature - + لا ميزة معتمدة + + + + Add Friend + أضف صديق - Add Friend - - - - Enter Xmpp ID: - + Add Friend... - + أضف صديق... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + أنا أسف... أنا مجرد وجود ألي مستخدم من قبل توماهوك (http://gettomahawk.com). في حال الحصول على هذه الرسالة، فإن الشخص اللذي تحاول الوصول إليه خارج الخدمة، فنرجو المحاولة لاحقاً! - + Authorize User أعطي الإذن للمستخدم - + Do you want to grant <b>%1</b> access to your Collection? - + هل تريد أن تسمح ل <b>%1</b> بالوصول إلى مجموعتك ؟ diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index e4c0451f2..01f91f865 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. След като бъде сканирана музикалната ти колекция, ще откриеш тук най-скоро добавените албуми. - + This collection doesn't have any recent albums. В тази колекция все още няма добавени наскоро албуми. @@ -895,67 +895,67 @@ Tomahaw създаде доклад относно това и изпращай QObject - + %n year(s) ago преди %n годинапреди %n години - + %n year(s) %n година%n години - + %n month(s) ago преди %n месецпреди %n месеца - + %n month(s) %n месец%n месеца - + %n week(s) ago преди %n седмицапреди %n седмици - + %n week(s) %n седмица%n седмици - + %n day(s) ago преди %n денпреди %n дена - + %n day(s) %n ден%n дена - + %n hour(s) ago преди %n часпреди %n часа - + %n hour(s) %n час %n часа - + %1 minutes ago преди %1 минути - + %1 minutes %1 минути - + just now току-що @@ -1624,12 +1624,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountModel - + Manual Install Required Изисква се ръчно инсталиране - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1739,12 +1739,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -2526,22 +2526,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Най-известни - + Artists Артисти - + Albums Албуми - + Tracks Песни @@ -2590,7 +2590,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Албуми @@ -2710,33 +2710,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканиране (%L1 песни) - + Scanning Сканирам - + Checking Проверявам - + Fetching Извличам - + Parsing Сортирам - + Saving (%1%) Запазвам (%1%) @@ -2783,38 +2783,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &Спри възпроизвеждането след текущата песен - - + + Hide Tomahawk Window Скрий главният прозорец - + Show Tomahawk Window Покажи главният прозорец - + Currently not playing. В момента не се изпълнява нищо - + Play Изпълни - + Pause Пауза - + &Continue Playback after current Track &Продължи възпроизвеждането след текущата песен @@ -3746,107 +3746,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Действие от потребителя - + Host is unknown Непознат адрес - + Item not found Обектът не е открит - + Authorization Error Грешка при даване на достъп - + Remote Stream Error Грешка в стриймът от отдалечената машина - + Remote Connection failed Отдалечената връзка е неуспешна - + Internal Server Error Вътрешна грешка на сървъра - + System shutdown Изключване на системата - + Conflict Конфликт - + Unknown Неизвестно - + No Compression Support Няма поддръжка на компресия - + No Encryption Support Няма поддръжка на криптиране - + No Authorization Support Няма поддръжка на удостоверяване - + No Supported Feature Неподдържана функция - + Add Friend Добави приятел - + Enter Xmpp ID: Въведи Xmpp ID: - + Add Friend... Добави приятел... - + XML Console... XML Конзола... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Извинявай.. Аз съм режимът за автоматични отговори изпълзван от Tomahawk. ( http://gettomahawk.com ) Щом получаваш това съобщение, този с който се опитваш да се свържеш вероятно не е на линия. Моля, опитай отново по-късно. - + Authorize User Оправомощяване на потребител - + Do you want to grant <b>%1</b> access to your Collection? Искате ли да позволите на <b>%1</b> достъп до вашата колекция? diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index ce7802730..4773ea7fc 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Després d'escanejar la vostra col·lecció musical, aquí trobareu els àlbums afegits últimament. - + This collection doesn't have any recent albums. Aquesta col·lecció no té àlbums recents. @@ -892,67 +892,67 @@ connect and stream from you? QObject - + %n year(s) ago fa %n anyfa %n anys - + %n year(s) %n any%n anys - + %n month(s) ago fa %n mesfa %n mesos - + %n month(s) %n mes%n mesos - + %n week(s) ago fa %n setmanafa %n setmanes - + %n week(s) %n setmana%n setmanes - + %n day(s) ago fa %n diafa %n dies - + %n day(s) %n dia%n dies - + %n hour(s) ago fa %n horafa %n hores - + %n hour(s) %n hora%n hores - + %1 minutes ago fa %1 minut - + %1 minutes %1 minuts - + just now ara mateix @@ -1619,12 +1619,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1734,12 +1734,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -2520,22 +2520,22 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top General - + Artists Artistes - + Albums Àlbums - + Tracks Cançons @@ -2584,7 +2584,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Àlbums @@ -2704,33 +2704,33 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::Source - - + + Scanning (%L1 tracks) Escanejant (%L1 cançons) - + Scanning Escanejant - + Checking Comprovant - + Fetching Cercant - + Parsing Analitzant - + Saving (%1%) Desant (%1%) @@ -2777,38 +2777,38 @@ introduïu el PIN aquí: TomahawkTrayIcon - + &Stop Playback after current Track &Atura la Reproducció després d'aquesta Cançó - - + + Hide Tomahawk Window Amaga la finestra de Tomahawk - + Show Tomahawk Window Mostra la finestra de Tomahawk - + Currently not playing. No s'està reproduint res. - + Play Reprodueix - + Pause Pausa - + &Continue Playback after current Track &Continua la reproducció després d'aquesta Cançó @@ -3737,107 +3737,107 @@ Lletres de la cancó "%1" de %2: XmppSipPlugin - + User Interaction Interacció d'usuari - + Host is unknown El nom de l'ordinador és desconegut - + Item not found No s'ha trobat l'element - + Authorization Error Error d'autorització - + Remote Stream Error Error de flux remot - + Remote Connection failed Ha fallat la connexió remota - + Internal Server Error Error del servidor intern - + System shutdown Sistema apagat - + Conflict Conflicte - + Unknown Desconegut - + No Compression Support Compressió no suportada - + No Encryption Support Encriptació no suportada - + No Authorization Support Autorització no suportada - + No Supported Feature Característica no suportada - + Add Friend Afegeix un Amic - + Enter Xmpp ID: Introduiu la ID XMPP: - + Add Friend... Afegeix un Amic... - + XML Console... Consola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Sóc una presència automàtica emprada pel Reproductor Tomahawk. (http://gettomahawk.com. Si rebeu aquest missatge, la persona amb qui intenteu contactar probablement no està en línia, intenteu-ho més tard! - + Authorize User Autorització d'Usuari - + Do you want to grant <b>%1</b> access to your Collection? Voleu permetre que <b>%1</b> accedeixi a la vostra Col·lecció? diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index ae66ce38f..ceb9f2839 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Nachdem Tomahawk deine Sammlung durchsucht hast siehst du hier deine neuesten Alben. - + This collection doesn't have any recent albums. Diese Sammlung ist leer. @@ -892,67 +892,67 @@ connect and stream from you? QObject - + %n year(s) ago vor %n Jahrvor %n Jahren - + %n year(s) %n Jahr%n Jahre - + %n month(s) ago vor %n Monatvor %n Monaten - + %n month(s) %n Monat%n Monate - + %n week(s) ago vor %n Wochevor %n Wochen - + %n week(s) %n Woche%n Wochen - + %n day(s) ago vor %n Tagvor %n Tagen - + %n day(s) %n Tag%n Tage - + %n hour(s) ago vor %n Stundevor %n Stunden - + %n hour(s) %n Stunde%n Stunden - + %1 minutes ago vor %1 Minute - + %1 minutes %1 Minuten - + just now gerade eben @@ -1616,12 +1616,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1731,12 +1731,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + Stop syncing with Spotify Synchronisation beenden @@ -2515,22 +2515,22 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Allgemein - + Artists Künstler - + Albums Alben - + Tracks Stücke @@ -2579,7 +2579,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Alben @@ -2699,33 +2699,33 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanne (%L1 Stücke) - + Scanning Scanne - + Checking Überprüfe - + Fetching Sammle - + Parsing Parse - + Saving (%1%) Speichere (%1%) @@ -2772,38 +2772,38 @@ Tomahawk auf Twitter's Website authentifiziert hast: TomahawkTrayIcon - + &Stop Playback after current Track Wiedergabe nach diesem Lied &stoppen - - + + Hide Tomahawk Window Tomahawk verbergen - + Show Tomahawk Window Tomahawk anzeigen - + Currently not playing. Derzeit wird nichts gespielt. - + Play Abspielen - + Pause Pause - + &Continue Playback after current Track Wiedergabe nach diesem Lied &fortsetzen @@ -3726,107 +3726,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Nutzer Interaktion - + Host is unknown Host ist unbekannt - + Item not found Eintrag nicht gefunden - + Authorization Error Authentifizierungs Fehler - + Remote Stream Error - + Remote Connection failed - + Internal Server Error Interner Server Fehler - + System shutdown - + Conflict Konflikt - + Unknown Unbekannt - + No Compression Support Keine Kompressions Option - + No Encryption Support Keine Verschluesselungs Option - + No Authorization Support Keine Authorisierungs Option - + No Supported Feature Keine unterstuetzte Faehigkeit - + Add Friend Freund hinzufügen... - + Enter Xmpp ID: XMPP-Benutzer: - + Add Friend... Freund hinzufügen... - + XML Console... XML-Konsole... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorisiere Nutzer - + Do you want to grant <b>%1</b> access to your Collection? Willst du <b>%1</b> Zugriff auf deine Sammlung gewähren? diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 6fec66a33..4d003909d 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. This collection doesn't have any recent albums. @@ -893,67 +893,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutes ago - + %1 minutes %1 minutes - + just now just now @@ -1620,12 +1620,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1735,12 +1735,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + Stop syncing with Spotify Stop syncing with Spotify @@ -2521,22 +2521,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Overall - + Artists Artists - + Albums Albums - + Tracks Tracks @@ -2585,7 +2585,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -2705,33 +2705,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanning (%L1 tracks) - + Scanning Scanning - + Checking Checking - + Fetching Fetching - + Parsing Parsing - + Saving (%1%) Saving (%1%) @@ -2778,38 +2778,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &Stop Playback after current Track - - + + Hide Tomahawk Window Hide Tomahawk Window - + Show Tomahawk Window Show Tomahawk Window - + Currently not playing. Currently not playing. - + Play Play - + Pause Pause - + &Continue Playback after current Track &Continue Playback after current Track @@ -3742,107 +3742,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction User Interaction - + Host is unknown Host is unknown - + Item not found Item not found - + Authorization Error Authorization Error - + Remote Stream Error Remote Stream Error - + Remote Connection failed Remote Connection failed - + Internal Server Error Internal Server Error - + System shutdown System shutdown - + Conflict Conflict - + Unknown Unknown - + No Compression Support No Compression Support - + No Encryption Support No Encryption Support - + No Authorization Support No Authorization Support - + No Supported Feature No Supported Feature - + Add Friend Add Friend - + Enter Xmpp ID: Enter Xmpp ID: - + Add Friend... Add Friend... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorize User - + Do you want to grant <b>%1</b> access to your Collection? Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 6a9d70506..5175d7389 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Tras haber escaneado su colección aquí encontrará los últimos álbumes añadidos. - + This collection doesn't have any recent albums. Esta colección no tiene álbumes recientes. @@ -891,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago hace %n añohace%n años - + %n year(s) %n año%n años - + %n month(s) ago hace %n meshace %n meses - + %n month(s) %n mes%n meses - + %n week(s) ago hace %n semanahace %n semanas - + %n week(s) %n semana%n semanas - + %n day(s) ago hace %n díahace %n días - + %n day(s) %n día%n días - + %n hour(s) ago hace %n horahace %n horas - + %n hour(s) %n hora%n horas - + %1 minutes ago hace %1 minutos - + %1 minutes %1 minutos - + just now justo ahora @@ -1618,12 +1618,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1733,12 +1733,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -2519,22 +2519,22 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top total - + Artists Artistas - + Albums Álbumes - + Tracks Pistas @@ -2583,7 +2583,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Álbumes @@ -2703,33 +2703,33 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 pistas) - + Scanning Escaneando - + Checking Comprobando - + Fetching Obteniendo - + Parsing Analizando - + Saving (%1%) Guardando (%1%) @@ -2776,38 +2776,38 @@ introduzca su número PIN aquí: TomahawkTrayIcon - + &Stop Playback after current Track &Para la Reproducción después de este Tema - - + + Hide Tomahawk Window Ocultar ventana de Tomahawk - + Show Tomahawk Window Mostrar ventana de Tomahawk - + Currently not playing. Ninguna pista en reproducción. - + Play Reproducir - + Pause Pausar - + &Continue Playback after current Track &Continuar la Reproducción después de este Tema @@ -3739,107 +3739,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction Interacción de usuario - + Host is unknown Máquina desconocida - + Item not found Elemento no encontrado - + Authorization Error Error de Autorización - + Remote Stream Error Error de Stream Remoto - + Remote Connection failed Fallo en la Conexión Remota - + Internal Server Error Error de Servidor Interno - + System shutdown Sistema apagado - + Conflict Conflicto - + Unknown Desconocido - + No Compression Support Compresión no sportada - + No Encryption Support Encriptación no soportada - + No Authorization Support Autorización no soportada - + No Supported Feature Característica no soportada - + Add Friend Añadir Amigo - + Enter Xmpp ID: Introducir ID XMPP: - + Add Friend... Añadir Amigo... - + XML Console... Consola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Lo siento -- soy una presencia automática usada por el Reproductor Tomahawk (http://gettomahawk.com). Si recibe este mensaje, la persona con quién intenta contactar no esté contectada probablemente. Inténtelo más tarde! - + Authorize User Autorizar Usuario - + Do you want to grant <b>%1</b> access to your Collection? ¿Quiere permitir que <b>%1</b> acceda a su Colección? diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 33b99d3d3..bbed5d4ae 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -161,12 +161,12 @@ se connecter et streamer depuis chez vous ? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Après avoir scanné votre collection musicale, vous trouverez les derniers albums ajoutés ici. - + This collection doesn't have any recent albums. Cette collection n'a pas d'albums récents @@ -199,7 +199,7 @@ se connecter et streamer depuis chez vous ? After you have scanned your music collection you will find your tracks right here. - Après avoir scanné votre collection musicale, vous trouverez vos pistes ici. + Après avoir scanné votre collection musicale, vous trouverez tous vos titres ici. @@ -385,17 +385,17 @@ se connecter et streamer depuis chez vous ? <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Désolé !</span>&nbsp;Tomahawk a planté. Dites-nous ce qui ne va pas ! Tomahawk a créé un rapport d'erreur qui sera utile pour améliorer la stabilité des prochaines versions. Vous pouvez dès maintenant envoyer ce rapport aux développeurs de Tomahawk.</p></body></html> Send this report - + Envoyer le rapport Don't send - + Ne pas envoyer @@ -538,7 +538,7 @@ se connecter et streamer depuis chez vous ? Scrobble tracks to Last.fm - Scrobbler les pistes sur Last.fm + Scrobbler les titres sur Last.fm @@ -558,7 +558,7 @@ se connecter et streamer depuis chez vous ? Import Playback History - + Importer l'historique @@ -628,7 +628,7 @@ se connecter et streamer depuis chez vous ? Saved tracks - Pistes sauvegardés + Titres sauvegardés @@ -672,62 +672,62 @@ se connecter et streamer depuis chez vous ? Artist - + Artiste Title - + Titre Composer - + Compositeur Album - + Album Track - + Piste Duration - + Durée Bitrate - + Bitrate Age - + Age Year - + Année Size - + Taille Origin - + Origine Score - + Score @@ -776,12 +776,12 @@ se connecter et streamer depuis chez vous ? All tracks by %1 on album %2 - Toutes les pistes par %1 sur l'album %2 + Tous les titres de %1 sur l'album %2 All tracks by %1 - Toutes les pistes par %1 + Tous les titres de %1 @@ -794,7 +794,7 @@ se connecter et streamer depuis chez vous ? Just a regular old playlist... Give it a name, drag in some tracks, and go! - Juste une liste de lecture normale... Donnez lui un nom, faites glisser quelques pistes et c'est parti ! + Une liste de lecture toute simple... Donnez lui un nom, faites glisser quelques pistes et c'est parti ! @@ -893,67 +893,67 @@ se connecter et streamer depuis chez vous ? QObject - + %n year(s) ago il y a %n anil y a %n ans - + %n year(s) %n an%n ans - + %n month(s) ago il y a %n moisil y a %n mois - + %n month(s) %n mois%n mois - + %n week(s) ago il y a %n semaineil y a %n semaines - + %n week(s) %n semaine%n semaines - + %n day(s) ago il y a %n jouril y a %n jours - + %n day(s) %n jour%n jours - + %n hour(s) ago il y a %n heureil y a %n heures - + %n hour(s) %n heure%n heures - + %1 minutes ago il y a %1 minutes - + %1 minutes %1 minutes - + just now à l'instant @@ -1095,7 +1095,7 @@ se connecter et streamer depuis chez vous ? Most Played Tracks You Don't Have - Pistes les plus joués que vous n'avez pas + Titres les plus joués que vous n'avez pas @@ -1176,7 +1176,7 @@ se connecter et streamer depuis chez vous ? All available tracks - Toutes les pistes disponibles + Tous les titres disponibles @@ -1211,7 +1211,7 @@ se connecter et streamer depuis chez vous ? Recently Played Tracks - Dernières pistes jouées + Dernières titres joués @@ -1250,7 +1250,7 @@ se connecter et streamer depuis chez vous ? Loved Tracks - Pistes favorites + Titres favoris @@ -1265,22 +1265,22 @@ se connecter et streamer depuis chez vous ? Latest additions to %1's collection - Derniers à la collection de %1 + Derniers ajouts à la collection de %1 Recently Played Tracks - Dernières pistes jouées + Derniers titres joués Your recently played tracks - Vos dernières pistes jouées + Les derniers titres que vous avez joués %1's recently played tracks - Dernières pistes jouées par %1 + Derniers titres joués par %1 @@ -1361,7 +1361,7 @@ se connecter et streamer depuis chez vous ? Top Loved Tracks - Top des pistes favorites + Top des titres favoris @@ -1551,7 +1551,7 @@ et des stations basés sur vos goûts. Filter by capability: - Filtrer par capacité : + Filtrer par fonctionnalité : @@ -1576,12 +1576,12 @@ et des stations basés sur vos goûts. Send reports after Tomahawk crashed - Envoyer un rapport apès un crash de Tomahawk + Envoyer un rapport après un crash de Tomahawk Allow web browsers to interact with Tomahawk (recommended) - Permettrre aux navigateurs web pour intéragir avec Tomahawk (recommandé) + Permettre aux navigateurs web d’interagir avec Tomahawk (recommandé) @@ -1620,14 +1620,14 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Installation manuelle requise - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + Malheureusement, l'installatio automatique de ce script de résolution n'est pas encore possible sous Linux.<br /><br />Utilisez le bouton "Installer depuis un fichier" ci-dessus en le récupérant pour votre distribution ou en le compilant. Des instructions complémentaires sont disponibles ici : <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1687,7 +1687,7 @@ et des stations basés sur vos goûts. Testing... - + Test... @@ -1698,22 +1698,22 @@ et des stations basés sur vos goûts. Importing %1 e.g. Importing 2012/01/01 - + Importation %1 Importing History... - + Import de l'historique History Incomplete. Resume - + Historique incomplet. Reprendre Playback History Imported - + Historique de lecture importé @@ -1735,12 +1735,12 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -1781,7 +1781,7 @@ et des stations basés sur vos goûts. Connect to your Twitter followers. - Se connecter à votre followers sur Twitter + Se connecter à vos followers sur Twitter @@ -1977,7 +1977,7 @@ Essayez de vous authentifier de nouveau. &Show Track Page - + &Afficher la page de la piste @@ -1987,12 +1987,12 @@ Essayez de vous authentifier de nouveau. &Show Album Page - + &Afficher la page de l'album &Show Artist Page - + &Afficher la page artiste @@ -2000,32 +2000,32 @@ Essayez de vous authentifier de nouveau. Top Loved Tracks - Top des pistes favorites + Top des titres favoris Your loved tracks - Vos pistes favorites + Vos titres favoris %1's loved tracks - Pistes favorites de %1 + Titres favoris de %1 The most loved tracks from all your friends - Les pistes favorites de tous vos amis + Les titres favoris de vos amis All of your loved tracks - Toutes vos pistes favorites + Tous vos titres favoris All of %1's loved tracks - Toutes les pistes favorites de %1 + Tous les titres favoris de %1 @@ -2105,7 +2105,7 @@ Veuillez changer les filtres et essayez de nouveau. Station ran out of tracks! Try tweaking the filters for a new set of songs to play. - Il n'y a plus de pistes dans la station ! + Il n'y a plus de chansons dans la station ! Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. @@ -2521,22 +2521,22 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top global - + Artists Artistes - + Albums Albums - + Tracks Pistes @@ -2559,17 +2559,17 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Top Tracks - Top des pistes + Top des titres Loved Tracks - Pistes favorites + Titres favoris Hyped Tracks - Pistes Hype + Titres Hype @@ -2585,7 +2585,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -2705,33 +2705,33 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Source - - + + Scanning (%L1 tracks) - Scan en cours (%L1 pistes) + Scan en cours (%L1 titres) - + Scanning Scan en cours - + Checking Vérification - + Fetching Chargement - + Parsing Décodage - + Saving (%1%) Enregistrement (%1%) @@ -2771,45 +2771,45 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. After authenticating on Twitter's web site, enter the displayed PIN number here: - Après vous être authentifier sur le site de Twitter, + Après vous être authentifié sur le site de Twitter, saisissez le numéro PIN ici : TomahawkTrayIcon - + &Stop Playback after current Track &Stopper la lecture après cette piste - - + + Hide Tomahawk Window Masquer la fenêtre Tomahawk - + Show Tomahawk Window Afficher la fenêtre Tomahawk - + Currently not playing. Pas de lecture en cours - + Play Lecture - + Pause Pause - + &Continue Playback after current Track &Continuer la lecture après cette piste @@ -2975,22 +2975,22 @@ saisissez le numéro PIN ici : Back - + Retour Go back one page - + Reculer d'une page Forward - + Avancer Go forward one page - + Avancer d'une page @@ -3048,7 +3048,7 @@ saisissez le numéro PIN ici : Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. Vérifiez que vous avez un backend Phonon et les plugins requis installés. + Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. @@ -3098,7 +3098,7 @@ saisissez le numéro PIN ici : Error connecting to SIP: Authentication failed! - + Erreur de connexion SIP : échec de l'authentification ! @@ -3249,7 +3249,7 @@ saisissez le numéro PIN ici : Lyrics - + Paroles @@ -3381,7 +3381,7 @@ saisissez le numéro PIN ici : The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - Le plugin Twitter vous permet de découvrir et jouer de la musique de vos amis Twitter qui utilisent Tomahawk et de poster des messages sur votre compte. + Le plugin Twitter vous permet de découvrir et jouer la musique de vos amis Twitter utilisant Tomahawk et de publier des messages sur votre compte. @@ -3464,12 +3464,12 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env Recently Played Tracks - Dernières pistes jouées + Derniers titres joués Recently played tracks from all your friends - Dernières pistes jouées par vos amis + Derniers titres joués par vos amis @@ -3686,7 +3686,7 @@ Paroles de "%1" par %2 : Login Information - Information de login + Informations de connexion @@ -3742,107 +3742,107 @@ Paroles de "%1" par %2 : XmppSipPlugin - + User Interaction Interaction utilisateur - + Host is unknown L'hôte est inconnu - + Item not found Objet non trouvé - + Authorization Error Erreur d'autorisation - + Remote Stream Error Erreur de lecture à distance - + Remote Connection failed Erreur de connexion à distance - + Internal Server Error Erreur interne du serveur - + System shutdown Arrêt du système - + Conflict Conflit - + Unknown Ajouter un &ami... - + No Compression Support Pas de support de la compression - + No Encryption Support Pas de support du chiffrement - + No Authorization Support Pas de support de l'authorization - + No Supported Feature Fonctionnalité non supportée - + Add Friend Ajouter un ami - + Enter Xmpp ID: Entrer l'ID XMPP - + Add Friend... Ajouter un ami... - + XML Console... Console XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Désolé -- Je suis une présence automatique utilisé par le lecteur Tomahawk (http://gettomahawk.com). Si vous lisez ce message, la personne que vous essayez de joindre n'est probablement pas connecter, donc essayez plus tard ! Merci ! - + Authorize User Autoriser l'utilisateur - + Do you want to grant <b>%1</b> access to your Collection? Voulez vous donner accès à votre collection à %1 ? diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index fe4bc11f5..0db23252a 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -891,69 +891,69 @@ connect and stream from you? QObject - + %n year(s) ago one: %n年前 other: %n年前 - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1分前 - + %1 minutes %1分 - + just now 只今 @@ -1617,12 +1617,12 @@ other: %n年前 Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1732,12 +1732,12 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2511,22 +2511,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2575,7 +2575,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2695,33 +2695,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning 走査中 - + Checking - + Fetching 取得中 - + Parsing 解析中 - + Saving (%1%) @@ -2767,38 +2767,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Tomahawkのウインドウを隠す - + Show Tomahawk Window Tomahawkのウインドウを表示 - + Currently not playing. - + Play 再生 - + Pause 一時停止 - + &Continue Playback after current Track @@ -3716,107 +3716,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index f1b18344c..c8671732d 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Po zeskanowaniu swojej kolekcji muzycznej w tym miejscu znajdziesz ostatnio dodane albumy. - + This collection doesn't have any recent albums. Ta kolekcja nie zawiera żadnych nowo dodanych albumów. @@ -891,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago %n rok temu%n lata temu%n lat temu - + %n year(s) %n rok%n lata%n lat - + %n month(s) ago %n miesiąc temu%n miesiące temu%n miesięcy temu - + %n month(s) %n miesiąc%n miesiące%n miesięcy - + %n week(s) ago %n tydzień temu%n tygodnie temu%n tygodni temu - + %n week(s) %n tydzień%n tygodnie%n tygodni - + %n day(s) ago %n dzień temu%n dni temu%n dni temu - + %n day(s) %n dzień%n dni%n dni - + %n hour(s) ago %n godzinę temu%n godziny temu%n godzin temu - + %n hour(s) %n godzinę%n godziny%n godzin - + %1 minutes ago %1 minut temu - + %1 minutes %1 minut - + just now przed chwilą @@ -1619,12 +1619,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1734,12 +1734,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2515,22 +2515,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Top Wszechczasów - + Artists Artyści - + Albums Albumy - + Tracks Utwory @@ -2579,7 +2579,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albumy @@ -2699,33 +2699,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Skanowanie (%L1 utworów) - + Scanning Skanowanie - + Checking Sprawdzanie - + Fetching Pobieranie - + Parsing Analizowanie - + Saving (%1%) Zapisywanie (%1%) @@ -2772,38 +2772,38 @@ wprowadź pokazany numer PIN tutaj: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Ukryj Okno Tomahawka - + Show Tomahawk Window Pokaż Okno Tomahawka - + Currently not playing. Aktualnie nie odtwarza. - + Play Odtwarzaj - + Pause Pauza - + &Continue Playback after current Track @@ -3732,107 +3732,107 @@ Tekst dla "%1" wykonawcy %2: XmppSipPlugin - + User Interaction - + Host is unknown Nieznany Host - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed Połączenie sieciowe się nie powiodło - + Internal Server Error Wewnętrzny błąd serwera - + System shutdown Wyłączenie systemu - + Conflict Konflikt - + Unknown Nieznany - + No Compression Support Brak obsługi kompresji - + No Encryption Support Brak obsługi szyfrowania - + No Authorization Support Brak obsługi autoryzacji - + No Supported Feature Brak obsługi danej funkcji - + Add Friend Dodaj Znajomego - + Enter Xmpp ID: - + Add Friend... Dodaj Znajomego... - + XML Console... Konsola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Autoryzuj Użytkownika - + Do you want to grant <b>%1</b> access to your Collection? Czy chcesz udzielić dostępu do swojej kolekcji <b>%1</b>? diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index ac3fef10e..69e7a7a5e 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Depois que você escanear a sua biblioteca musical você encontrará aqui o último álbum adicionado. - + This collection doesn't have any recent albums. Essa biblioteca não tem nenhum álbum recente. @@ -891,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutos atrás - + %1 minutes %1 minutos - + just now agora @@ -1618,12 +1618,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1733,12 +1733,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2514,22 +2514,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall Classificação geral - + Artists Artistas - + Albums Álbuns - + Tracks Faixas @@ -2578,7 +2578,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2698,33 +2698,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 faixas) - + Scanning Escaneando - + Checking Verificando - + Fetching Buscando - + Parsing Analisando - + Saving (%1%) Guardando (%1%) @@ -2771,38 +2771,38 @@ colocar o número PIN mostrado aqui: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Esconder janela do Tomahawk - + Show Tomahawk Window Mostrar janela do Tomahawk - + Currently not playing. Não reproduzindo nada. - + Play Reporduzir - + Pause Pausar - + &Continue Playback after current Track @@ -3732,107 +3732,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found Item não encontrado - + Authorization Error - + Remote Stream Error - + Remote Connection failed Conexão Remota falhou - + Internal Server Error - + System shutdown - + Conflict - + Unknown Desconhecido - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend Adicionar Amigo - + Enter Xmpp ID: - + Add Friend... Adicionar Amigo... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Autorizar Usuário - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 45bd49a7e..f5c0bbecf 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. После сканирования вашей музыкальной коллекции вы найдете свой альбомы тут. - + This collection doesn't have any recent albums. Эта коллекция не имеет последних альбомов. @@ -893,67 +893,67 @@ connect and stream from you? QObject - + %n year(s) ago %n год назад%n года назад%n лет назад - + %n year(s) %n год%n года%n лет - + %n month(s) ago %n месяц назад%n месяца назад%n месяцей назад - + %n month(s) %n месяц%n месяца%n месяцей - + %n week(s) ago %n неделю назад%n недели назад%n недель назад - + %n week(s) %n неделю%n недели%n недель - + %n day(s) ago %n день назад%n дня назад%n дней назад - + %n day(s) %n день%n дня%n дней - + %n hour(s) ago %n час назад%n часа назад%n часов назад - + %n hour(s) %n час%n часа%n часов - + %1 minutes ago %1 минут(ы) назад - + %1 minutes %1 минут(ы) - + just now только что @@ -1617,12 +1617,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1732,12 +1732,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -2516,22 +2516,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Исполнители - + Albums Альбомы - + Tracks Песни @@ -2580,7 +2580,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Альбом @@ -2700,33 +2700,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканирование (%L1 песни) - + Scanning Сканирую - + Checking Проверяю - + Fetching Выбираю - + Parsing Анализирую - + Saving (%1%) Сохраняю (%1%) @@ -2772,38 +2772,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &Остановить после текущего трека - - + + Hide Tomahawk Window Спрятать окно Tomahawk - + Show Tomahawk Window Показать окно Tomahawk - + Currently not playing. Не воспроизводится. - + Play Играть - + Pause Пауза - + &Continue Playback after current Track &Продолжить воспроизведение после текущего трека @@ -3731,107 +3731,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Взаимодействие с пользователем - + Host is unknown Неизвестный хост - + Item not found Песня не найдена - + Authorization Error Ошибка авторизации - + Remote Stream Error Удаленный поток ошибок - + Remote Connection failed Ошибка подключения - + Internal Server Error Внутренняя ошибка сервера - + System shutdown Выключение системы - + Conflict Конфликт - + Unknown Неизвестный - + No Compression Support Нет поддержки сжатия - + No Encryption Support Нет поддержки шифрования - + No Authorization Support Нет поддержки авторизации - + No Supported Feature Не поддерживаемые функции - + Add Friend Добавить друга - + Enter Xmpp ID: Введите XMPP ID: - + Add Friend... Добавить друга... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Авторизация пользователя - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 0aeb744fb..6882e826c 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda album här. - + This collection doesn't have any recent albums. Den här samlingen inga nya album. @@ -892,67 +892,67 @@ connect and stream from you? QObject - + %n year(s) ago %n år sedan%n år sedan - + %n year(s) %n år sedan%n år sedan - + %n month(s) ago %n månad sedan%n månader sedan - + %n month(s) %n månad%n månader - + %n week(s) ago %n vecka sedan%n veckor sedan - + %n week(s) %n vecka%n veckor - + %n day(s) ago %n dag sedan%n dagar sedan - + %n day(s) %n dag%n dagar - + %n hour(s) ago %n timme sedan%n timmar sedan - + %n hour(s) %n timme%n timmar - + %1 minutes ago %1 minuter sedan - + %1 minutes %1 minuter - + just now precis nyss @@ -1616,12 +1616,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1731,12 +1731,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2510,22 +2510,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists Artister - + Albums Album - + Tracks Spår @@ -2574,7 +2574,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2694,33 +2694,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Söker igenom (%L1 spår) - + Scanning - + Checking Kontrollerar - + Fetching Hämtar - + Parsing Tolkar - + Saving (%1%) Sparar (%1%) @@ -2766,38 +2766,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Dölj Tomahawk-fönstret - + Show Tomahawk Window Visa Tomahawk-fönstret - + Currently not playing. Spelar ingenting för närvarande. - + Play Spela upp - + Pause Paus - + &Continue Playback after current Track @@ -3715,107 +3715,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index cc73d23c4..db27ad047 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Müzik koleksiyonunuzu taradıktan sonra en son eklenen albümleri burada bulacaksınız. - + This collection doesn't have any recent albums. Bu koleksiyonda en son eklenen bir albüm yok. @@ -891,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -1615,12 +1615,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1730,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2509,22 +2509,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2573,7 +2573,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2693,33 +2693,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) @@ -2765,38 +2765,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + &Continue Playback after current Track @@ -3714,107 +3714,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 7bf37c6e5..3a730a7cf 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -891,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -1615,12 +1615,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1730,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2509,22 +2509,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2573,7 +2573,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -2693,33 +2693,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) @@ -2765,38 +2765,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + &Continue Playback after current Track @@ -3714,107 +3714,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index a5e79d8fe..eba246551 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. 當您掃描您的音樂收藏,您會發現您的最新專輯添加在這裡。 - + This collection doesn't have any recent albums. 這個收藏沒有任何最新專輯。 @@ -891,67 +891,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1 分鐘前 - + %1 minutes %1 分鐘 - + just now 剛才 @@ -1615,12 +1615,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1730,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -2509,22 +2509,22 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists 演出者 - + Albums 專輯 - + Tracks 曲目 @@ -2573,7 +2573,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums 專輯 @@ -2693,33 +2693,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing 解析 - + Saving (%1%) @@ -2765,38 +2765,38 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. 目前沒有播放。 - + Play 播放 - + Pause 暫停 - + &Continue Playback after current Track @@ -3715,107 +3715,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction 使用者互動 - + Host is unknown 主機是未知 - + Item not found - + Authorization Error 授權錯誤 - + Remote Stream Error 遠端串流錯誤 - + Remote Connection failed 遠端連線失敗 - + Internal Server Error 內部服務器錯誤 - + System shutdown 系統關閉 - + Conflict 衝突 - + Unknown 未知 - + No Compression Support 沒有壓縮支持 - + No Encryption Support 沒有加密支持 - + No Authorization Support 沒有授權支持 - + No Supported Feature 沒有支持的功能 - + Add Friend 加為好友 - + Enter Xmpp ID: 輸入XMPP識別碼: - + Add Friend... 加為好友... - + XML Console... XML的控制台... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User 授權用戶 - + Do you want to grant <b>%1</b> access to your Collection? From 6b1aa6e9cdcf682bd4d639e45a3c4925ee929ef5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 23 May 2012 17:54:42 +0200 Subject: [PATCH 046/433] * According to Leo this is even faster. --- src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp index c97fcf558..d72716e01 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp @@ -139,7 +139,7 @@ DatabaseCommand_AllAlbums::execForCollection( DatabaseImpl* dbi ) QString sql = QString( "SELECT DISTINCT album.id, album.name, album.artist, artist.name " - "FROM file, file_join, album " + "FROM file_join, file, album " "LEFT OUTER JOIN artist ON album.artist = artist.id " "WHERE file.id = file_join.file " "AND file_join.album = album.id " From b0a99ad1ad0faa8a9030b914dc604bb2336354c3 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 00:25:47 +0200 Subject: [PATCH 047/433] * Style cleanup. --- src/Scrobbler.cpp | 12 +++++------- src/libtomahawk/resolvers/QtScriptResolver.cpp | 1 + 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Scrobbler.cpp b/src/Scrobbler.cpp index 8b5fa5456..8c3285161 100644 --- a/src/Scrobbler.cpp +++ b/src/Scrobbler.cpp @@ -44,8 +44,8 @@ Scrobbler::Scrobbler( QObject* parent ) SLOT( engineTick( unsigned int ) ), Qt::QueuedConnection ); connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); connect( AudioEngine::instance(), SIGNAL( started( const Tomahawk::result_ptr& ) ), SLOT( trackStarted( const Tomahawk::result_ptr& ) ), Qt::QueuedConnection ); @@ -72,16 +72,13 @@ void Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) { Q_ASSERT( QThread::currentThread() == thread() ); -// qDebug() << Q_FUNC_INFO; - if( m_reachedScrobblePoint ) + if ( m_reachedScrobblePoint ) { m_reachedScrobblePoint = false; scrobble(); } - QVariantMap playInfo; - Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["title"] = track->track(); trackInfo["artist"] = track->artist()->name(); @@ -89,6 +86,7 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) trackInfo["duration"] = QString::number( track->duration() ); trackInfo["albumpos"] = QString::number( track->albumpos() ); + QVariantMap playInfo; playInfo["trackinfo"] = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); playInfo["private"] = TomahawkSettings::instance()->privateListeningMode(); @@ -126,7 +124,7 @@ Scrobbler::trackStopped() { Q_ASSERT( QThread::currentThread() == thread() ); - if( m_reachedScrobblePoint ) + if ( m_reachedScrobblePoint ) { m_reachedScrobblePoint = false; scrobble(); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 3cacfe102..ca40016c0 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -312,6 +312,7 @@ QtScriptResolver::init() m_ready = true; } + void QtScriptResolver::start() { From 41d0c9b15388ed3a116e0d4563723c455f6f5e5e Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Thu, 24 May 2012 01:10:03 +0200 Subject: [PATCH 048/433] unused_variable_warnings-- --- src/libtomahawk/accounts/AccountModel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 9b1a6809e..c5b341289 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -101,6 +101,8 @@ AccountModel::loadData() qDebug() << "All accounts after remove:"; foreach ( Account* acct, allAccounts ) qDebug() << acct->accountFriendlyName() << "\t" << acct->accountId(); // All other accounts we haven't dealt with yet +#else + Q_UNUSED( removed ); #endif } } else From 606fb9cae5792f144710d27cfae1bc5384fff23d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 07:50:20 +0200 Subject: [PATCH 049/433] * Defines in headers are just evil. --- src/libtomahawk/audio/AudioEngine.cpp | 21 ++++++++++++++++++--- src/libtomahawk/audio/AudioEngine.h | 8 +++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 57b22ac2b..c13815534 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2012, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify @@ -39,13 +39,14 @@ #include "utils/Logger.h" - using namespace Tomahawk; -AudioEngine* AudioEngine::s_instance = 0; +#define AUDIO_VOLUME_STEP 5 static QString s_aeInfoIdentifier = QString( "AUDIOENGINE" ); +AudioEngine* AudioEngine::s_instance = 0; + AudioEngine* AudioEngine::instance() @@ -302,6 +303,20 @@ AudioEngine::setVolume( int percentage ) } +void +AudioEngine::lowerVolume() +{ + setVolume( volume() - AUDIO_VOLUME_STEP ); +} + + +void +AudioEngine::raiseVolume() +{ + setVolume( volume() + AUDIO_VOLUME_STEP ); +} + + void AudioEngine::mute() { diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index c5e3aeac8..ac1c2ded4 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2012, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell * * Tomahawk is free software: you can redistribute it and/or modify @@ -35,8 +35,6 @@ #include "DllMacro.h" -#define AUDIO_VOLUME_STEP 5 - class DLLEXPORT AudioEngine : public QObject { @@ -88,8 +86,8 @@ public slots: void seek( qint64 ms ); void seek( int ms ); // for compatibility with seekbar in audiocontrols void setVolume( int percentage ); - void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); } - void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); } + void lowerVolume(); + void raiseVolume(); void mute(); void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result ); From 32254071181b88380e9f098e394bf9797daf1c5b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 07:55:34 +0200 Subject: [PATCH 050/433] * Fixed incorrect PixmapDelegateFader connect()s. --- src/libtomahawk/utils/PixmapDelegateFader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/utils/PixmapDelegateFader.cpp b/src/libtomahawk/utils/PixmapDelegateFader.cpp index f3adac4e4..7fe2f5dab 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.cpp +++ b/src/libtomahawk/utils/PixmapDelegateFader.cpp @@ -51,7 +51,7 @@ PixmapDelegateFader::PixmapDelegateFader( const artist_ptr& artist, const QSize& { if ( !m_artist.isNull() ) { - connect( m_artist.data(), SIGNAL( updated() ), SLOT( trackChanged() ) ); + connect( m_artist.data(), SIGNAL( updated() ), SLOT( artistChanged() ) ); connect( m_artist.data(), SIGNAL( coverChanged() ), SLOT( artistChanged() ) ); m_currentReference = m_artist->cover( size, forceLoad ); } @@ -67,7 +67,7 @@ PixmapDelegateFader::PixmapDelegateFader( const album_ptr& album, const QSize& s { if ( !m_album.isNull() ) { - connect( m_album.data(), SIGNAL( updated() ), SLOT( trackChanged() ) ); + connect( m_album.data(), SIGNAL( updated() ), SLOT( albumChanged() ) ); connect( m_album.data(), SIGNAL( coverChanged() ), SLOT( albumChanged() ) ); m_currentReference = m_album->cover( size, forceLoad ); } From b51e7390ba944e271da973e3650acdc5aa698cd7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 10:44:33 +0200 Subject: [PATCH 051/433] * Ok, let's try that publicly. AudioState queue to work around the Phonon state mess. --- src/libtomahawk/audio/AudioEngine.cpp | 62 ++++++++++++++++++++++++--- src/libtomahawk/audio/AudioEngine.h | 11 +++-- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index c13815534..1c8fce52a 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -133,9 +133,7 @@ AudioEngine::play() if ( isPaused() ) { - setVolume( m_volume ); - m_mediaObject->play(); - setVolume( m_volume ); + queueState( Playing ); emit resumed(); sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowResumed ); @@ -151,7 +149,8 @@ AudioEngine::pause() tDebug( LOGEXTRA ) << Q_FUNC_INFO; m_volume = volume(); - m_mediaObject->pause(); + + queueState( Paused ); emit paused(); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( Tomahawk::InfoSystem::InfoPushData( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPaused, QVariant(), Tomahawk::InfoSystem::PushNoFlag ) ); @@ -185,7 +184,6 @@ AudioEngine::stop( AudioErrorCode errorCode ) sendWaitingNotification(); Tomahawk::InfoSystem::InfoPushData pushData( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowStopped, QVariant(), Tomahawk::InfoSystem::PushNoFlag ); - Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); } @@ -485,8 +483,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) m_input.clear(); } m_input = io; - m_mediaObject->play(); - + queueState( Playing ); emit started( m_currentTrack ); if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate ) @@ -734,6 +731,16 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) } } } + + if ( newState == Phonon::PausedState || newState == Phonon::PlayingState ) + { + tDebug() << "Phonon state now:" << newState; + if ( m_stateQueue.count() ) + { + AudioState qState = m_stateQueue.dequeue(); + checkStateQueue(); + } + } } @@ -835,6 +842,47 @@ AudioEngine::isLocalResult( const QString& url ) const } +void +AudioEngine::checkStateQueue() +{ + if ( m_stateQueue.count() ) + { + AudioState state = m_stateQueue.head(); + tDebug() << "Applying state command:" << state; + switch ( state ) + { + case Playing: + { + setVolume( m_volume ); + m_mediaObject->play(); + setVolume( m_volume ); + } + + case Paused: + { + m_mediaObject->pause(); + } + } + } + else + tDebug() << "Queue is empty"; +} + + +void +AudioEngine::queueState( AudioState state ) +{ + tDebug() << "Enqueuing state command:" << state << m_stateQueue.count(); + + m_stateQueue.enqueue( state ); + + if ( m_stateQueue.count() == 1 ) + { + checkStateQueue(); + } +} + + void AudioEngine::setState( AudioState state ) { diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index ac1c2ded4..040552c15 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -29,13 +30,12 @@ #include "libtomahawk/infosystem/InfoSystem.h" -#include "Result.h" #include "Typedefs.h" +#include "Result.h" #include "PlaylistInterface.h" #include "DllMacro.h" - class DLLEXPORT AudioEngine : public QObject { Q_OBJECT @@ -139,6 +139,9 @@ private slots: void sendWaitingNotification() const; private: + void checkStateQueue(); + void queueState( AudioState state ); + void setState( AudioState state ); bool isHttpResult( const QString& ) const; @@ -162,9 +165,11 @@ private: bool m_waitingOnNewTrack; mutable QStringList m_supportedMimeTypes; - AudioState m_state; unsigned int m_volume; + AudioState m_state; + QQueue< AudioState > m_stateQueue; + static AudioEngine* s_instance; }; From 8abf255b270420e78e1babe3d33659ce2c286f2f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 11:00:28 +0200 Subject: [PATCH 052/433] * Changed debug output and style cleanup. --- src/libtomahawk/accounts/ResolverAccount.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 4e7921702..29cecc757 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -72,7 +72,6 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact ResolverAccount::ResolverAccount( const QString& accountId ) : Account( accountId ) { - const QString path = configuration()[ "path" ].toString(); setTypes( AccountType( ResolverType ) ); @@ -141,7 +140,7 @@ ResolverAccount::authenticate() if ( m_resolver.isNull() ) return; - qDebug() << Q_FUNC_INFO << "Authenticating/starting resolver, exists?" << m_resolver; + tDebug() << Q_FUNC_INFO << "Authenticating/starting resolver, exists?" << m_resolver.data()->name(); if ( !m_resolver.data()->running() ) m_resolver.data()->start(); @@ -259,9 +258,9 @@ AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QS AtticaResolverAccount::~AtticaResolverAccount() { - } + void AtticaResolverAccount::loadIcon() { @@ -274,7 +273,6 @@ AtticaResolverAccount::loadIcon() if ( codeDir.exists() && codeDir.exists( "icon.png" ) ) m_icon.load( codeDir.absoluteFilePath( "icon.png" ) ); - } From c036c147a738b747acb84c1ef557c59948b9dff1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 11:01:00 +0200 Subject: [PATCH 053/433] * Leo: please review. I think this was meant to be this way actually. --- src/libtomahawk/accounts/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 22ab46d78..69d5cdd45 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -232,7 +232,7 @@ void AccountManager::connectAll() { tDebug( LOGVERBOSE ) << Q_FUNC_INFO; - foreach( Account* acc, m_accounts ) + foreach( Account* acc, m_enabledAccounts ) { acc->authenticate(); m_enabledAccounts << acc; From cbda055c89353fc0f337941b199b2c4c0c9f8cfe Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 12:10:30 +0200 Subject: [PATCH 054/433] * Fixed enabling all resolvers on startup. --- src/libtomahawk/accounts/ResolverAccount.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 29cecc757..5113892da 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -124,7 +124,9 @@ ResolverAccount::init( const QString& path ) void ResolverAccount::hookupResolver() { - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString(), true ) ) ); + tDebug() << "Hooking up resolver:" << configuration().value( "path" ).toString() << enabled(); + + m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString(), enabled() ) ) ); connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); // What resolver do we have here? Should only be types that are 'real' resolvers From 4b059293d1e6dddb1c2509cc2af29a65f7d9c8cf Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 12:34:52 +0200 Subject: [PATCH 055/433] * Clear command queue when Phonon reports an error. --- src/libtomahawk/audio/AudioEngine.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 1c8fce52a..9a918d334 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -686,8 +686,6 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) emit error( UnknownError ); setState( Error ); - - return; } if ( newState == Phonon::PlayingState ) { @@ -732,7 +730,7 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) } } - if ( newState == Phonon::PausedState || newState == Phonon::PlayingState ) + if ( newState == Phonon::PausedState || newState == Phonon::PlayingState || newState == Phonon::ErrorState ) { tDebug() << "Phonon state now:" << newState; if ( m_stateQueue.count() ) From c574dfeff3c1af944bfe7bfd1f67774ee4834709 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 13:42:02 +0200 Subject: [PATCH 056/433] * Added some queueState safety mechanism. Phonon's error signal fails to fire sometimes. Sigh. --- src/libtomahawk/audio/AudioEngine.cpp | 18 +++++++++++++++++- src/libtomahawk/audio/AudioEngine.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 9a918d334..16849d37f 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -80,6 +80,10 @@ AudioEngine::AudioEngine() connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), SLOT( onVolumeChanged( qreal ) ) ); + m_stateQueueTimer.setInterval( 5000 ); + m_stateQueueTimer.setSingleShot( true ); + connect( &m_stateQueueTimer, SIGNAL( timeout() ), SLOT( queueStateSafety() ) ); + onVolumeChanged( m_audioOutput->volume() ); #ifndef Q_WS_X11 @@ -867,17 +871,29 @@ AudioEngine::checkStateQueue() } +void +AudioEngine::queueStateSafety() +{ + tDebug() << Q_FUNC_INFO; + m_stateQueue.clear(); +} + + void AudioEngine::queueState( AudioState state ) { - tDebug() << "Enqueuing state command:" << state << m_stateQueue.count(); + if ( m_stateQueueTimer.isActive() ) + m_stateQueueTimer.stop(); + tDebug() << "Enqueuing state command:" << state << m_stateQueue.count(); m_stateQueue.enqueue( state ); if ( m_stateQueue.count() == 1 ) { checkStateQueue(); } + + m_stateQueueTimer.start(); } diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index 040552c15..79848a736 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -137,6 +137,8 @@ private slots: void onPlaylistNextTrackReady(); void sendWaitingNotification() const; + + void queueStateSafety(); private: void checkStateQueue(); @@ -169,6 +171,7 @@ private: AudioState m_state; QQueue< AudioState > m_stateQueue; + QTimer m_stateQueueTimer; static AudioEngine* s_instance; }; From ca7db4ff99edcff4216bd0eb71c7aa29c3305b4f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 13:49:41 +0200 Subject: [PATCH 057/433] * Fixed artist / album search results. --- src/libtomahawk/widgets/SearchWidget.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libtomahawk/widgets/SearchWidget.cpp b/src/libtomahawk/widgets/SearchWidget.cpp index 30a9a84c5..a5bd24715 100644 --- a/src/libtomahawk/widgets/SearchWidget.cpp +++ b/src/libtomahawk/widgets/SearchWidget.cpp @@ -53,11 +53,6 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent ) m_artistsModel = new AlbumModel( ui->artistView ); ui->artistView->setAlbumModel( m_artistsModel ); - ui->artistView->setAutoFitItems( false ); - ui->albumView->setAutoFitItems( false ); - ui->artistView->setSpacing( 8 ); - ui->albumView->setSpacing( 8 ); - ui->artistView->proxyModel()->sort( -1 ); ui->albumView->proxyModel()->sort( -1 ); From a150697f49bf56887ec94360459098321f8f1f26 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 14:08:42 +0200 Subject: [PATCH 058/433] * DRY and style cleanups. --- src/libtomahawk/ViewManager.cpp | 14 -------------- src/libtomahawk/playlist/AlbumView.cpp | 3 +++ src/libtomahawk/playlist/ArtistView.cpp | 4 ++++ src/libtomahawk/playlist/CustomPlaylistView.cpp | 3 --- src/libtomahawk/playlist/QueueView.cpp | 2 -- src/libtomahawk/playlist/TrackView.cpp | 4 ++++ src/libtomahawk/playlist/dynamic/DynamicView.cpp | 5 ----- src/libtomahawk/widgets/NewReleasesWidget.cpp | 4 ---- src/libtomahawk/widgets/SearchWidget.cpp | 12 ------------ src/libtomahawk/widgets/SocialPlaylistWidget.cpp | 7 +------ src/libtomahawk/widgets/WelcomeWidget.cpp | 4 ---- src/libtomahawk/widgets/WhatsHotWidget.cpp | 7 ------- .../widgets/infowidgets/AlbumInfoWidget.cpp | 5 ----- .../widgets/infowidgets/ArtistInfoWidget.cpp | 7 ------- .../widgets/infowidgets/SourceInfoWidget.cpp | 7 ------- .../widgets/infowidgets/TrackInfoWidget.cpp | 4 ---- 16 files changed, 12 insertions(+), 80 deletions(-) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 6d1255bb2..07b9ba533 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -97,16 +97,12 @@ ViewManager::ViewManager( QObject* parent ) m_superCollectionView = new ArtistView(); m_superCollectionModel = new TreeModel( m_superCollectionView ); m_superCollectionView->setTreeModel( m_superCollectionModel ); - m_superCollectionView->setFrameShape( QFrame::NoFrame ); - m_superCollectionView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); m_superCollectionView->setShowModes( false ); // m_superCollectionView->proxyModel()->setShowOfflineResults( false ); m_superAlbumView = new AlbumView(); m_superAlbumModel = new AlbumModel( m_superAlbumView ); m_superAlbumView->setAlbumModel( m_superAlbumModel ); - m_superAlbumView->setFrameShape( QFrame::NoFrame ); - m_superAlbumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); m_stack->setContentsMargins( 0, 0, 0, 0 ); m_widget->setContentsMargins( 0, 0, 0, 0 ); @@ -149,8 +145,6 @@ ViewManager::createPageForPlaylist( const playlist_ptr& pl ) PlaylistModel* model = new PlaylistModel(); view->setPlaylistModel( model ); model->loadPlaylist( pl ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); pl->resolve(); m_playlistViews.insert( pl, view ); @@ -290,8 +284,6 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) view = new CollectionView(); CollectionFlatModel* model = new CollectionFlatModel(); view->setPlayableModel( model ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->addCollection( collection ); @@ -314,8 +306,6 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) view = new ArtistView(); TreeModel* model = new TreeModel(); view->setTreeModel( model ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); model->addCollection( collection ); @@ -338,8 +328,6 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) aview = new AlbumView(); AlbumModel* amodel = new AlbumModel( aview ); aview->setAlbumModel( amodel ); - aview->setFrameShape( QFrame::NoFrame ); - aview->setAttribute( Qt::WA_MacShowFocusRect, 0 ); amodel->addCollection( collection ); m_collectionAlbumViews.insert( collection, aview ); @@ -490,8 +478,6 @@ ViewManager::showRecentPlaysPage() if ( !m_recentPlaysWidget ) { PlaylistView* pv = new PlaylistView( m_widget ); - pv->setFrameShape( QFrame::NoFrame ); - pv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); RecentlyPlayedModel* raModel = new RecentlyPlayedModel( source_ptr(), pv ); raModel->setTitle( tr( "Recently Played Tracks" ) ); diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 8ac620a16..03c5eaa8b 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -52,6 +52,9 @@ AlbumView::AlbumView( QWidget* parent ) , m_contextMenu( new ContextMenu( this ) ) , m_inited( false ) { + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + setDragEnabled( true ); setDropIndicatorShown( false ); setDragDropOverwriteMode( false ); diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/ArtistView.cpp index 0dcf8c5e0..993a875b6 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/ArtistView.cpp @@ -55,6 +55,10 @@ ArtistView::ArtistView( QWidget* parent ) , m_contextMenu( new ContextMenu( this ) ) , m_showModes( true ) { + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + setContentsMargins( 0, 0, 0, 0 ); setAlternatingRowColors( true ); setDragEnabled( true ); setDropIndicatorShown( false ); diff --git a/src/libtomahawk/playlist/CustomPlaylistView.cpp b/src/libtomahawk/playlist/CustomPlaylistView.cpp index 742e8f443..7ba352c03 100644 --- a/src/libtomahawk/playlist/CustomPlaylistView.cpp +++ b/src/libtomahawk/playlist/CustomPlaylistView.cpp @@ -34,9 +34,6 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c , m_model( new PlaylistModel( this ) ) { // Generate the tracks, add them to the playlist - setFrameShape( QFrame::NoFrame ); - setAttribute( Qt::WA_MacShowFocusRect, 0 ); - m_model->setStyle( PlayableModel::Large ); setPlaylistModel( m_model ); generateTracks(); diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 1134f21e0..0c4985bdc 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -45,8 +45,6 @@ QueueView::QueueView( AnimatedSplitter* parent ) ui->queue->setProxyModel( new QueueProxyModel( ui->queue ) ); ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); - ui->queue->setFrameShape( QFrame::NoFrame ); - ui->queue->setAttribute( Qt::WA_MacShowFocusRect, 0 ); ui->queue->overlay()->setEnabled( false ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index 9bbc109ff..af3cb230e 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -57,6 +57,10 @@ TrackView::TrackView( QWidget* parent ) , m_updateContextView( true ) , m_contextMenu( new ContextMenu( this ) ) { + setFrameShape( QFrame::NoFrame ); + setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + setContentsMargins( 0, 0, 0, 0 ); setMouseTracking( true ); setAlternatingRowColors( true ); setSelectionMode( QAbstractItemView::ExtendedSelection ); diff --git a/src/libtomahawk/playlist/dynamic/DynamicView.cpp b/src/libtomahawk/playlist/dynamic/DynamicView.cpp index d55c03065..47ebc8d3c 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicView.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicView.cpp @@ -49,10 +49,6 @@ DynamicView::DynamicView( QWidget* parent ) , m_fadebg( false ) , m_fadeOnly( false ) { - setContentsMargins( 0, 0, 0, 0 ); - setFrameShape( QFrame::NoFrame ); - setAttribute( Qt::WA_MacShowFocusRect, 0 ); - m_fadeOutAnim.setDuration( FADE_LENGTH ); m_fadeOutAnim.setCurveShape( QTimeLine::LinearCurve ); m_fadeOutAnim.setFrameRange( 100, 0 ); @@ -71,7 +67,6 @@ DynamicView::DynamicView( QWidget* parent ) DynamicView::~DynamicView() { - } diff --git a/src/libtomahawk/widgets/NewReleasesWidget.cpp b/src/libtomahawk/widgets/NewReleasesWidget.cpp index f3ae283fe..e57820603 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.cpp +++ b/src/libtomahawk/widgets/NewReleasesWidget.cpp @@ -60,9 +60,6 @@ NewReleasesWidget::NewReleasesWidget( QWidget* parent ) { ui->setupUi( this ); - ui->albumsView->setFrameShape( QFrame::NoFrame ); - ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout_2 ); TomahawkUtils::unmarginLayout( ui->breadCrumbLeft->layout() ); @@ -76,7 +73,6 @@ NewReleasesWidget::NewReleasesWidget( QWidget* parent ) connect( ui->breadCrumbLeft, SIGNAL( activateIndex( QModelIndex ) ), SLOT( leftCrumbIndexChanged(QModelIndex) ) ); - //m_playlistInterface = Tomahawk::playlistinterface_ptr( new ChartsPlaylistInterface( this ) ); m_workerThread = new QThread( this ); diff --git a/src/libtomahawk/widgets/SearchWidget.cpp b/src/libtomahawk/widgets/SearchWidget.cpp index a5bd24715..b99d462b5 100644 --- a/src/libtomahawk/widgets/SearchWidget.cpp +++ b/src/libtomahawk/widgets/SearchWidget.cpp @@ -58,18 +58,6 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent ) TomahawkUtils::unmarginLayout( ui->verticalLayout ); - ui->artistView->setContentsMargins( 0, 0, 0, 0 ); - ui->artistView->setFrameShape( QFrame::NoFrame ); - ui->artistView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - ui->albumView->setContentsMargins( 0, 0, 0, 0 ); - ui->albumView->setFrameShape( QFrame::NoFrame ); - ui->albumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - ui->resultsView->setContentsMargins( 0, 0, 0, 0 ); - ui->resultsView->setFrameShape( QFrame::NoFrame ); - ui->resultsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->resultsView->loadingSpinner()->fadeIn(); m_queries << Tomahawk::Query::get( search, uuid() ); diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index 69572d81f..8f0eb5202 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -36,7 +36,7 @@ QString SocialPlaylistWidget::s_mostPlayedPlaylistsQuery = "asd"; QString SocialPlaylistWidget::s_topForeignTracksQuery = "select track.name, artist.name, count(*) as counter from (select track from playback_log group by track, source), track, artist where track not in (select track from playback_log where source is null group by track) and track.id = track and artist.id = track.artist group by track order by counter desc"; SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) - : QWidget ( parent ) + : QWidget( parent ) , ui( new Ui_SocialPlaylistWidget ) , m_topForeignTracksModel( 0 ) , m_popularNewAlbumsModel( 0 ) @@ -53,10 +53,6 @@ SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) ui->mostPlayedPlaylists->setFrameShape( QFrame::NoFrame ); ui->mostPlayedPlaylists->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->newTracksView->setFrameShape( QFrame::NoFrame ); - ui->newTracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->newAlbumsView->setFrameShape( QFrame::NoFrame ); - ui->newAlbumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); @@ -94,7 +90,6 @@ SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) SocialPlaylistWidget::~SocialPlaylistWidget() { - } diff --git a/src/libtomahawk/widgets/WelcomeWidget.cpp b/src/libtomahawk/widgets/WelcomeWidget.cpp index 1411799bc..75b8f1846 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.cpp +++ b/src/libtomahawk/widgets/WelcomeWidget.cpp @@ -54,10 +54,6 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->playlistWidget->setFrameShape( QFrame::NoFrame ); ui->playlistWidget->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->tracksView->setFrameShape( QFrame::NoFrame ); - ui->tracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->additionsView->setFrameShape( QFrame::NoFrame ); - ui->additionsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index c57f3601c..4cc7b7ca7 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -59,9 +59,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) { ui->setupUi( this ); - ui->albumsView->setFrameShape( QFrame::NoFrame ); - ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->stackLeft->layout() ); TomahawkUtils::unmarginLayout( ui->horizontalLayout->layout() ); @@ -78,8 +75,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) connect( ui->breadCrumbLeft, SIGNAL( activateIndex( QModelIndex ) ), SLOT( leftCrumbIndexChanged(QModelIndex) ) ); - ui->tracksViewLeft->setFrameShape( QFrame::NoFrame ); - ui->tracksViewLeft->setAttribute( Qt::WA_MacShowFocusRect, 0 ); ui->tracksViewLeft->overlay()->setEnabled( false ); ui->tracksViewLeft->setHeaderHidden( true ); ui->tracksViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); @@ -93,8 +88,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) artistsProxy->setDynamicSortFilter( true ); ui->artistsViewLeft->setProxyModel( artistsProxy ); - ui->artistsViewLeft->setFrameShape( QFrame::NoFrame ); - ui->artistsViewLeft->setAttribute( Qt::WA_MacShowFocusRect, 0 ); ui->artistsViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); ui->artistsViewLeft->header()->setVisible( true ); diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index aab6d209d..4f84b29f5 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -46,11 +46,6 @@ AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* par { ui->setupUi( this ); - ui->albumsView->setFrameShape( QFrame::NoFrame ); - ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->tracksView->setFrameShape( QFrame::NoFrame ); - ui->tracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->verticalLayout ); TomahawkUtils::unmarginLayout( ui->verticalLayout_2 ); diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 7a32abff6..0ac2be33d 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -53,13 +53,6 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* m_plInterface = Tomahawk::playlistinterface_ptr( new MetaPlaylistInterface( this ) ); - ui->albums->setFrameShape( QFrame::NoFrame ); - ui->albums->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->relatedArtists->setFrameShape( QFrame::NoFrame ); - ui->relatedArtists->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->topHits->setFrameShape( QFrame::NoFrame ); - ui->topHits->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->layoutWidget->layout() ); TomahawkUtils::unmarginLayout( ui->layoutWidget1->layout() ); diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp index 7dc557539..e6f51088a 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp @@ -43,13 +43,6 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* { ui->setupUi( this ); - ui->historyView->setFrameShape( QFrame::NoFrame ); - ui->historyView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->recentAlbumView->setFrameShape( QFrame::NoFrame ); - ui->recentAlbumView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->recentCollectionView->setFrameShape( QFrame::NoFrame ); - ui->recentCollectionView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - TomahawkUtils::unmarginLayout( layout() ); TomahawkUtils::unmarginLayout( ui->horizontalLayout ); TomahawkUtils::unmarginLayout( ui->verticalLayout ); diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 89faf53bd..b58f86023 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -67,10 +67,6 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par f.setPixelSize( 12 ); ui->statsLabel->setFont( f ); - ui->similarTracksView->setFrameShape( QFrame::NoFrame ); - ui->similarTracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->lyricsView->setFrameShape( QFrame::NoFrame ); - ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); // ui->similarTracksView->setStyleSheet( "QListView { background-color: transparent; } QListView::item { background-color: transparent; }" ); QPalette p = ui->trackLabel->palette(); From 0af1cc6e20783eb837e0c3f4e6e482447c99ab3f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 14:17:06 +0200 Subject: [PATCH 059/433] Revert "* Leo: please review. I think this was meant to be this way actually." This reverts commit c036c147a738b747acb84c1ef557c59948b9dff1. --- src/libtomahawk/accounts/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 69d5cdd45..22ab46d78 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -232,7 +232,7 @@ void AccountManager::connectAll() { tDebug( LOGVERBOSE ) << Q_FUNC_INFO; - foreach( Account* acc, m_enabledAccounts ) + foreach( Account* acc, m_accounts ) { acc->authenticate(); m_enabledAccounts << acc; From 1845bbbd65fadd5f654d8997b165c869e53dbd78 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 14:48:18 +0200 Subject: [PATCH 060/433] * No frame / focus rect for lyrics. --- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index b58f86023..29e4bc68e 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -52,6 +52,9 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->statsLabel->setStyleSheet( "QLabel { background-image:url(); border: 2px solid #dddddd; background-color: #faf9f9; border-radius: 4px; padding: 12px; }" ); ui->lyricsView->setStyleSheet( "QTextBrowser#lyricsView { background-color: transparent; }" ); + ui->lyricsView->setFrameShape( QFrame::NoFrame ); + ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + QFont f = font(); f.setBold( true ); f.setPixelSize( 18 ); From ac263789144ff043b2895b7e28a7b70a302adf6b Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 24 May 2012 08:57:48 -0400 Subject: [PATCH 061/433] Remove legacy/confusing autostart from pipeline's external resolvers --- src/accounts/lastfm/LastFmAccount.cpp | 2 +- src/accounts/spotify/SpotifyAccount.cpp | 2 +- src/libtomahawk/Pipeline.cpp | 4 +--- src/libtomahawk/Pipeline.h | 2 +- src/libtomahawk/accounts/ResolverAccount.cpp | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index 7cfbd8924..44433a6a2 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -288,7 +288,7 @@ LastFmAccount::hookupResolver() const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() ); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath, enabled() ) ) ); + m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath ) ) ); connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); } diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index 5805bcb00..7deb68499 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -159,7 +159,7 @@ SpotifyAccount::hookupResolver() } qDebug() << "Starting spotify resolver with path:" << path; - m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path, enabled() ) ) ); + m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path ) ) ); connect( m_spotifyResolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); connect( m_spotifyResolver.data(), SIGNAL( customMessage( QString,QVariantMap ) ), this, SLOT( resolverMessage( QString, QVariantMap ) ) ); diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index c3fd08114..5966ad7be 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -130,7 +130,7 @@ Pipeline::addExternalResolverFactory( ResolverFactoryFunc resolverFactory ) Tomahawk::ExternalResolver* -Pipeline::addScriptResolver( const QString& path, bool start ) +Pipeline::addScriptResolver( const QString& path ) { ExternalResolver* res = 0; @@ -141,8 +141,6 @@ Pipeline::addScriptResolver( const QString& path, bool start ) continue; m_scriptResolvers << QWeakPointer< ExternalResolver >( res ); - if ( start ) - res->start(); break; } diff --git a/src/libtomahawk/Pipeline.h b/src/libtomahawk/Pipeline.h index c142bb646..542298a3f 100644 --- a/src/libtomahawk/Pipeline.h +++ b/src/libtomahawk/Pipeline.h @@ -58,7 +58,7 @@ public: void reportArtists( QID qid, const QList< artist_ptr >& artists ); void addExternalResolverFactory( ResolverFactoryFunc resolverFactory ); - Tomahawk::ExternalResolver* addScriptResolver( const QString& scriptPath, bool start = true ); + Tomahawk::ExternalResolver* addScriptResolver( const QString& scriptPath ); void stopScriptResolver( const QString& scriptPath ); void removeScriptResolver( const QString& scriptPath ); QList< QWeakPointer< ExternalResolver > > scriptResolvers() const { return m_scriptResolvers; } diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 5113892da..30a3800e8 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -126,7 +126,7 @@ ResolverAccount::hookupResolver() { tDebug() << "Hooking up resolver:" << configuration().value( "path" ).toString() << enabled(); - m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString(), enabled() ) ) ); + m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString() ) ) ); connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); // What resolver do we have here? Should only be types that are 'real' resolvers From ca41b8b7d353a89d10518ca70f9c166ce4336c67 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 15:20:09 +0200 Subject: [PATCH 062/433] * Fixed resolving top hits top-to-bottom. --- src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 0ac2be33d..858e90f3a 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -235,13 +235,13 @@ ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestD int i = 0; foreach ( const QString& track, tracks ) { - queries << Query::get( m_artist->name(), track, QString() ); - Pipeline::instance()->resolve( queries ); + queries << Query::get( m_artist->name(), track, QString(), QString(), false ); if ( ++i == 15 ) break; } + Pipeline::instance()->resolve( queries ); m_topHitsModel->append( queries ); break; } From 305b69b229901aba6ef6d96bc1d8fbda95440540 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 15:26:02 +0200 Subject: [PATCH 063/433] * Only reset volume when resuming playback. --- src/libtomahawk/audio/AudioEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 16849d37f..35551bac9 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -855,9 +855,10 @@ AudioEngine::checkStateQueue() { case Playing: { - setVolume( m_volume ); + bool paused = isPaused(); m_mediaObject->play(); - setVolume( m_volume ); + if ( paused ) + setVolume( m_volume ); } case Paused: From fde130ef9f5aea4bc3001711e6f404ec8c0966c6 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 15:26:38 +0200 Subject: [PATCH 064/433] * Store volume when actually pausing. --- src/libtomahawk/audio/AudioEngine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 35551bac9..d7e777a76 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -152,8 +152,6 @@ AudioEngine::pause() { tDebug( LOGEXTRA ) << Q_FUNC_INFO; - m_volume = volume(); - queueState( Paused ); emit paused(); @@ -863,6 +861,7 @@ AudioEngine::checkStateQueue() case Paused: { + m_volume = volume(); m_mediaObject->pause(); } } From d14e14d25a0ddd76fe940cd04a4996aa98676551 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 24 May 2012 16:09:44 +0200 Subject: [PATCH 065/433] * Workaround for scrobbling duration-less results. --- src/accounts/lastfm/LastFmInfoPlugin.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/accounts/lastfm/LastFmInfoPlugin.cpp b/src/accounts/lastfm/LastFmInfoPlugin.cpp index 3217e9d51..30aed0d06 100644 --- a/src/accounts/lastfm/LastFmInfoPlugin.cpp +++ b/src/accounts/lastfm/LastFmInfoPlugin.cpp @@ -212,6 +212,11 @@ LastFmInfoPlugin::scrobble() return; tLog() << Q_FUNC_INFO << "Scrobbling now:" << m_track.toString(); + + // FIXME: workaround for the duration-less dilandau (and others) tracks + if ( m_track.duration() == 0 ) + m_track.setDuration( 31 ); + m_scrobbler->cache( m_track ); m_scrobbler->submit(); } From e571050758bce7275b4e82c101a9c37d565e45c9 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 24 May 2012 16:12:24 -0400 Subject: [PATCH 066/433] Make sure to re-enable resolver when overwriting attica with local installed --- src/accounts/spotify/SpotifyAccount.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index 7deb68499..a05dc6e5c 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -313,6 +313,7 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath ) if ( !m_spotifyResolver.isNull() ) { // replace + AccountManager::instance()->disableAccount( this ); NewClosure( m_spotifyResolver.data(), SIGNAL( destroyed() ), this, SLOT( hookupAfterDeletion( bool ) ), true ); m_spotifyResolver.data()->deleteLater(); } From 216e43a50261813464afd8b25fb0ce15234181c1 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Thu, 24 May 2012 22:16:44 +0000 Subject: [PATCH 067/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_bg.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_ca.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_de.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_en.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_es.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_fr.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_ja.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_pl.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_pt_BR.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_ru.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_sv.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_tr.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_zh_CN.ts | 82 +++++++++++++++++++++--------------------- lang/tomahawk_zh_TW.ts | 82 +++++++++++++++++++++--------------------- 15 files changed, 615 insertions(+), 615 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index df32880ca..edbfcfe26 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -134,7 +134,7 @@ connect and stream from you? ألبومات أخرى للفنان - + Other Albums by %1 ألبومات أخرى ل%1 @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. بعد إجراء مسح مجموعة أغانيك الخاصة ستجد ألبوماتك المضافة هنا. - + This collection doesn't have any recent albums. هذه المجموعة لا تحتوي على ألبومات جديدة. @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. - + This collection is currently empty. المجموعة فارغة حاليا. - + Sorry, your filter '%1' did not match any results. نتأسف، نظام البحث لم يجد شيئا تحت عنوان '%1'. @@ -991,12 +991,12 @@ connect and stream from you? - + Show Queue أظهر قائمة الانتظار - + Hide Queue إخفي قائمة الانتظار @@ -1215,17 +1215,17 @@ connect and stream from you? الأغاني التي إستمعت إليها مؤخرا - + New Additions الإضافة الجديدة - + My recent activity نشاطاتي الأخيرة - + Recent activity from %1 النشاطات المؤخرة ل %1 @@ -1620,12 +1620,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required مطلوب تثبيت يدوي - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على لنكس. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1735,12 +1735,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify أوقف المزامنة مع سبوتيفي (Spotify) @@ -1998,32 +1998,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks الأغاني المحبوبة الأكثر شهرة - + Your loved tracks الأغاني التي أحببتها - + %1's loved tracks الأغاني المحبوبة ل%1 - + The most loved tracks from all your friends الأغاني المحبوبة كثيرا بين أصدقائك - + All of your loved tracks جميع الأغاني التي أحببتها - + All of %1's loved tracks جميع الأغاني المحبوبة ل%1 @@ -2083,17 +2083,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! أدخل بعض الترشيحات أعلاه لتوزيع هذه الإذاعة! - + Press Generate to get started! إضغط "توليد" لتبدأ! - + Add some filters above, and press Generate to get started! أدخل بعض الترشيحات أعلاه ثم iضغط "توليد" لتبدأ! @@ -2557,27 +2557,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks أفضل الأغاني - + Loved Tracks الأغاني المحبوبة - + Hyped Tracks فقت الأغاني - + Top Artists أفضل الفنانين - + Hyped Artists فقت الفنانين @@ -3257,27 +3257,27 @@ enter the displayed PIN number here: أغاني قريبة - + You've listened to this track %n time(s). لقد استمعت إلى هذه الأغنية %n مرةلقد استمعت إلى هذه الأغنية مرة %nلقد استمعت إلى هذه الأغنية مرتين %nلقد استمعت إلى هذه الأغنية %n مراتلقد استمعت إلى هذه الأغنية %n مراتلقد استمعت إلى هذه الأغنية %n مرات - + You've never listened to this track before. لم تستمع لهذه الأغنية من قبل. - + You first listened to it on %1. استمعت إليها أولاً في %1 - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3285,7 +3285,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. عذراً، ترشيحك "%1" لم يطابق أي نتائج. @@ -3442,27 +3442,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection سوبر كولكشن - + Combined libraries of all your online friends جمع مكاتب أصدقائك الذين على الهواء - + All available albums جميع الألبومات الجديدة - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Recently played tracks from all your friends جميع الأغاني التي استمع إليها أصدقائك مؤخرا @@ -3485,7 +3485,7 @@ You can re-send a sync message at any time simply by sending another tweet using الأغاني التي إستمعت إليها مؤخرا - + No recently created playlists in your network. لا قوائم أغاني جديدة أنشئت مؤخرا على شبكتك. diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 01f91f865..8497710f6 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -133,7 +133,7 @@ connect and stream from you? Други албуми на този артист - + Other Albums by %1 Други албуми от %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. След като бъде сканирана музикалната ти колекция, ще откриеш тук най-скоро добавените албуми. - + This collection doesn't have any recent albums. В тази колекция все още няма добавени наскоро албуми. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. След като приключи сканирането на музикалната ти колекция, ще откриеш музиката си тук. - + This collection is currently empty. Базата данни с песни е празна. - + Sorry, your filter '%1' did not match any results. Съжалявам. Твоят филтър '%1' не върна никакъв резултат. @@ -992,12 +992,12 @@ Tomahaw създаде доклад относно това и изпращай - + Show Queue Покажи опашката - + Hide Queue Скрий опашката @@ -1216,17 +1216,17 @@ Tomahaw създаде доклад относно това и изпращай Наскоро изпълнени песни - + New Additions Нови попълнения - + My recent activity Скорошна активност - + Recent activity from %1 Скорошна активност на %1 @@ -1624,12 +1624,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountModel - + Manual Install Required Изисква се ръчно инсталиране - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1739,12 +1739,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -2004,32 +2004,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Най-харесвани песни - + Your loved tracks Песните, които харесам. - + %1's loved tracks Песните, каресвани от %1 - + The most loved tracks from all your friends Най-харесваните песни от всички твои приятели. - + All of your loved tracks Всички песни, които харесвам. - + All of %1's loved tracks Всички песни, харесвани от %1 @@ -2088,17 +2088,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Добави няколко критерия, за да разпространиш тази станция - + Press Generate to get started! Натисни "Генерирай" за да почне просвирване. - + Add some filters above, and press Generate to get started! Добави няколко критерия и натисни "Генерирай" за да почне просвирване. @@ -2562,27 +2562,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Най-слушани песни - + Loved Tracks Харесани песни - + Hyped Tracks Песни, изпъкващи сред останалите - + Top Artists Най-слушани артисти - + Hyped Artists Изпълнители, изпъкващи сред останалите @@ -3265,27 +3265,27 @@ enter the displayed PIN number here: Подобни песни - + You've listened to this track %n time(s). Ти си слушал тази песен %n път(и)Ти си слушал тази песен %n път(и) - + You've never listened to this track before. Никога не си слушал тази песен преди - + You first listened to it on %1. Първоначално си я слушал на %1 - + You've listened to %1 %n time(s). Слушал си %1 път(и)Слушал си %1 %n път(и) - + You've never listened to %1 before. Никога не си слушал %1 преди @@ -3293,7 +3293,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Съжалявам, твоят филтър %1 не върна никакъв резултат. @@ -3456,28 +3456,28 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Combined libraries of all your online friends Обща колекция с всичките ми приятели на линия - + All available albums Всички налични албуми - + Recently Played Tracks Наскоро изпълени песни - + Recently played tracks from all your friends Наскоро изпълнени песни от всичките ти приятели @@ -3500,7 +3500,7 @@ You can re-send a sync message at any time simply by sending another tweet using Наскоро изпълнени - + No recently created playlists in your network. Не откривам наскоро създадени списъци в твоята мрежа diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 4773ea7fc..bd305113d 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -133,7 +133,7 @@ connect and stream from you? Altres Àlbums de l'Artista - + Other Albums by %1 Altres Àlbums de %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Després d'escanejar la vostra col·lecció musical, aquí trobareu els àlbums afegits últimament. - + This collection doesn't have any recent albums. Aquesta col·lecció no té àlbums recents. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Després d'escanejar la vostra col·lecció musical, aquí trobareu les cançons afegides últimament. - + This collection is currently empty. Aquesta col·lecció es troba buida actualment. - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -989,12 +989,12 @@ connect and stream from you? - + Show Queue Mostra la Cua - + Hide Queue Amaga la Cua @@ -1213,17 +1213,17 @@ connect and stream from you? Cançons Escoltades Recentment - + New Additions Novetats - + My recent activity La meva activitat recent - + Recent activity from %1 Activitat recent de %1 @@ -1619,12 +1619,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1734,12 +1734,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -1997,32 +1997,32 @@ Torneu a autenticar-vos. Tomahawk::CustomPlaylistView - + Top Loved Tracks Top de Cançons Preferides - + Your loved tracks Les meves cançons preferides - + %1's loved tracks Les cançons preferides de %1 - + The most loved tracks from all your friends Les cançons preferides de tots els amics - + All of your loved tracks Totes les meves cançons preferides - + All of %1's loved tracks Totes les cançons preferides de %1 @@ -2082,17 +2082,17 @@ Canvieu els filtres o intenteu-ho de nou. Tomahawk::DynamicView - + Add some filters above to seed this station! Afegeiu slguns filtres per omplir aquesta emissora! - + Press Generate to get started! Premeu Genera per començar! - + Add some filters above, and press Generate to get started! Afegeiu alguns filtres i premeu Genera per començar! @@ -2556,27 +2556,27 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top Cançons Musicals - + Loved Tracks Cançons Preferides - + Hyped Tracks Cançons en alça - + Top Artists Top Artistes - + Hyped Artists Artistes en alça @@ -3256,27 +3256,27 @@ introduïu el PIN aquí: Cançons Semblants - + You've listened to this track %n time(s). Heu escoltat aquesta cançó %n cop.Heu escoltat aquesta cançó %n cops. - + You've never listened to this track before. No heu escoltat mai aquesta cançó abans. - + You first listened to it on %1. Vau escoltar aquesta cançó per primer cop el %1. - + You've listened to %1 %n time(s). Heu escoltat %1 %n cop.Heu escoltat %1 %n cops. - + You've never listened to %1 before. No heu escoltat mai %1 abans. @@ -3284,7 +3284,7 @@ introduïu el PIN aquí: TrackView - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -3446,27 +3446,27 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant ViewManager - + SuperCollection SuperCol·lecció - + Combined libraries of all your online friends Biblioteques combinades de tots els amis en línia - + All available albums Tots els àlbums disponibles - + Recently Played Tracks Cançons Escoltades Recentment - + Recently played tracks from all your friends Cançons escoltades recentment pels amics @@ -3489,7 +3489,7 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant Cançons Escoltades Recentment - + No recently created playlists in your network. No hi ha cançons escoltades recentment a la xarxa. diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index ceb9f2839..534ce3f2e 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -133,7 +133,7 @@ connect and stream from you? Andere Alben des Künstlers - + Other Albums by %1 Andere Alben von %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Nachdem Tomahawk deine Sammlung durchsucht hast siehst du hier deine neuesten Alben. - + This collection doesn't have any recent albums. Diese Sammlung ist leer. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Nachdem Tomahawk deine Sammlung durchsucht hat siehst du deine Lieder hier. - + This collection is currently empty. Diese Sammlung is momentan leer. - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -989,12 +989,12 @@ connect and stream from you? - + Show Queue Warteschlange einblenden - + Hide Queue Warteschlange ausblenden @@ -1213,17 +1213,17 @@ connect and stream from you? Kürzlich gehörte Lieder - + New Additions Kürzlich hinzugekommen - + My recent activity Meine letzten Aktivitäten - + Recent activity from %1 Die letzten Aktivitäten von %1 @@ -1616,12 +1616,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1731,12 +1731,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + Stop syncing with Spotify Synchronisation beenden @@ -1992,32 +1992,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Meist geliebte Lieder - + Your loved tracks Deine Lieblingslieder - + %1's loved tracks Die Lieblingslieder von %1 - + The most loved tracks from all your friends Die Lieblingslieder deiner Freunde - + All of your loved tracks All deine Lieblingslieder - + All of %1's loved tracks Alle Lieblingslieder von %1 @@ -2077,17 +2077,17 @@ Bitte ändere den Filter oder versuche es erneut. Tomahawk::DynamicView - + Add some filters above to seed this station! Füge einige Filter hinzu, um diese Station zu starten! - + Press Generate to get started! Drücke Erzeugen, und los geht's! - + Add some filters above, and press Generate to get started! Füge oben einige Filter hinzu und drücke Erzeugen um loszulegen! @@ -2551,27 +2551,27 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3251,27 +3251,27 @@ Tomahawk auf Twitter's Website authentifiziert hast: Ähnliche Lieder - + You've listened to this track %n time(s). Du hast dieses Lied einmal gehört.Du hast dieses Lied %n mal gehört. - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3279,7 +3279,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3436,27 +3436,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Kombinierte Sammlung all deiner Freunde - + All available albums Alle verfügbaren Alben - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3479,7 +3479,7 @@ You can re-send a sync message at any time simply by sending another tweet using Kürzlich gehörte Lieder - + No recently created playlists in your network. Es gibt keine kürzlich erstellten Playlisten in deinem Netzwerk. diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 4d003909d..9228c9c7c 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -134,7 +134,7 @@ connect and stream from you? Other Albums by Artist - + Other Albums by %1 Other Albums by %1 @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. This collection doesn't have any recent albums. @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. This collection is currently empty. - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -990,12 +990,12 @@ connect and stream from you? - + Show Queue Show Queue - + Hide Queue Hide Queue @@ -1214,17 +1214,17 @@ connect and stream from you? Recently Played Tracks - + New Additions New Additions - + My recent activity My recent activity - + Recent activity from %1 Recent activity from %1 @@ -1620,12 +1620,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1735,12 +1735,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + Stop syncing with Spotify Stop syncing with Spotify @@ -1998,32 +1998,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Top Loved Tracks - + Your loved tracks Your loved tracks - + %1's loved tracks %1's loved tracks - + The most loved tracks from all your friends The most loved tracks from all your friends - + All of your loved tracks All of your loved tracks - + All of %1's loved tracks All of %1's loved tracks @@ -2083,17 +2083,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Add some filters above to seed this station! - + Press Generate to get started! Press Generate to get started! - + Add some filters above, and press Generate to get started! Add some filters above, and press Generate to get started! @@ -2557,27 +2557,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top Tracks - + Loved Tracks Loved Tracks - + Hyped Tracks Hyped Tracks - + Top Artists Top Artists - + Hyped Artists Hyped Artists @@ -3257,27 +3257,27 @@ enter the displayed PIN number here: Similar Tracks - + You've listened to this track %n time(s). You've listened to this track %n time(s).You've listened to this track %n time(s). - + You've never listened to this track before. You've never listened to this track before. - + You first listened to it on %1. You first listened to it on %1. - + You've listened to %1 %n time(s). You've listened to %1 %n time(s).You've listened to %1 %n time(s). - + You've never listened to %1 before. You've never listened to %1 before. @@ -3285,7 +3285,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -3447,27 +3447,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Combined libraries of all your online friends - + All available albums All available albums - + Recently Played Tracks Recently Played Tracks - + Recently played tracks from all your friends Recently played tracks from all your friends @@ -3490,7 +3490,7 @@ You can re-send a sync message at any time simply by sending another tweet using Recently Played Tracks - + No recently created playlists in your network. No recently created playlists in your network. diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 5175d7389..b369935ef 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -133,7 +133,7 @@ connect and stream from you? Otros álbumes por el artista - + Other Albums by %1 Otros álbumes por %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Tras haber escaneado su colección aquí encontrará los últimos álbumes añadidos. - + This collection doesn't have any recent albums. Esta colección no tiene álbumes recientes. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Tras haber escaneado su colección aquí encontrará las últimas pistas añadidas. - + This collection is currently empty. Esta colección está vacía. - + Sorry, your filter '%1' did not match any results. Tu filtro '%1' no reportó ningún resultado. @@ -988,12 +988,12 @@ connect and stream from you? - + Show Queue Mostrar cola - + Hide Queue Ocultar cola @@ -1212,17 +1212,17 @@ connect and stream from you? Pistas reproducidas recientemente - + New Additions Nuevas adiciones - + My recent activity Mi actividad reciente - + Recent activity from %1 Actividad reciente de %1 @@ -1618,12 +1618,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1733,12 +1733,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -1996,32 +1996,32 @@ Hay que volverse a autenticar. Tomahawk::CustomPlaylistView - + Top Loved Tracks Pistas favoritas - + Your loved tracks Tus pistas favoritas - + %1's loved tracks Pistas favoritas de %1 - + The most loved tracks from all your friends Las pistas favoritas de tus amigos - + All of your loved tracks Todas tus pistas favoritas - + All of %1's loved tracks Todas las pistas favoritas de %1 @@ -2081,17 +2081,17 @@ Por favor, cambie los filtros o inténtelo de nuevo. Tomahawk::DynamicView - + Add some filters above to seed this station! ¡Añada algunos filtros para la estación! - + Press Generate to get started! ¡Seleccione Generar para comenzar! - + Add some filters above, and press Generate to get started! ¡Añada algunos filtros, y seleccione Generar para comenzar! @@ -2555,27 +2555,27 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Temas más escuchados - + Loved Tracks Temas Favoritos - + Hyped Tracks Temas a la alza - + Top Artists Artistas más escuchados - + Hyped Artists Artistas a la alza @@ -3255,27 +3255,27 @@ introduzca su número PIN aquí: Temas Similares - + You've listened to this track %n time(s). Ha escuchado esta canción %n vez.Ha escuchado esta canción %n veces. - + You've never listened to this track before. Nunca ha escuchado este tema antes. - + You first listened to it on %1. Escuchó este tema pro primera vez en %1. - + You've listened to %1 %n time(s). Ha escuchado %1 %n vez.Ha escuchado %1 %n veces. - + You've never listened to %1 before. Nunca ha escuchado %1 antes. @@ -3283,7 +3283,7 @@ introduzca su número PIN aquí: TrackView - + Sorry, your filter '%1' did not match any results. Lo siento, tu filtro '%1' no ha encontrado resultados. @@ -3445,27 +3445,27 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en ViewManager - + SuperCollection SuperColección - + Combined libraries of all your online friends Bibliotecas combinadas de todos tus amigos conectados - + All available albums Todos los álbumes disponibles - + Recently Played Tracks Temas Escuchados Recientemente - + Recently played tracks from all your friends Temas escuchados recientemente por mis amigos @@ -3488,7 +3488,7 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en Pistas reproducidas recientemente - + No recently created playlists in your network. No hay listas de reproducción recientemente creadas en su red. diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index bbed5d4ae..adb30ef95 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -134,7 +134,7 @@ se connecter et streamer depuis chez vous ? Tous les albums par cet artiste - + Other Albums by %1 Autres albums par %1 @@ -161,12 +161,12 @@ se connecter et streamer depuis chez vous ? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Après avoir scanné votre collection musicale, vous trouverez les derniers albums ajoutés ici. - + This collection doesn't have any recent albums. Cette collection n'a pas d'albums récents @@ -197,17 +197,17 @@ se connecter et streamer depuis chez vous ? ArtistView - + After you have scanned your music collection you will find your tracks right here. Après avoir scanné votre collection musicale, vous trouverez tous vos titres ici. - + This collection is currently empty. La collection est vide actuellement. - + Sorry, your filter '%1' did not match any results. Désolé, votre filtre '%1' ne correspond à aucun résultat @@ -990,12 +990,12 @@ se connecter et streamer depuis chez vous ? - + Show Queue Afficher la file d'attente - + Hide Queue Masquer la file d'attente @@ -1214,17 +1214,17 @@ se connecter et streamer depuis chez vous ? Dernières titres joués - + New Additions Nouveaux ajouts - + My recent activity Mon activité récente - + Recent activity from %1 Activité récente de %1 @@ -1620,12 +1620,12 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::AccountModel - + Manual Install Required Installation manuelle requise - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Malheureusement, l'installatio automatique de ce script de résolution n'est pas encore possible sous Linux.<br /><br />Utilisez le bouton "Installer depuis un fichier" ci-dessus en le récupérant pour votre distribution ou en le compilant. Des instructions complémentaires sont disponibles ici : <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1735,12 +1735,12 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -1998,32 +1998,32 @@ Essayez de vous authentifier de nouveau. Tomahawk::CustomPlaylistView - + Top Loved Tracks Top des titres favoris - + Your loved tracks Vos titres favoris - + %1's loved tracks Titres favoris de %1 - + The most loved tracks from all your friends Les titres favoris de vos amis - + All of your loved tracks Tous vos titres favoris - + All of %1's loved tracks Tous les titres favoris de %1 @@ -2083,17 +2083,17 @@ Veuillez changer les filtres et essayez de nouveau. Tomahawk::DynamicView - + Add some filters above to seed this station! Ajoutez des filtres ci dessus pour commencer une station ! - + Press Generate to get started! Appuyez sur Générer pour commencer ! - + Add some filters above, and press Generate to get started! Ajoutez des filtres ci dessus et appuyez sur "Générer" pour commencer ! @@ -2557,27 +2557,27 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top des titres - + Loved Tracks Titres favoris - + Hyped Tracks Titres Hype - + Top Artists Top Artistes - + Hyped Artists Artistes Hype @@ -3257,27 +3257,27 @@ saisissez le numéro PIN ici : Piste similaire - + You've listened to this track %n time(s). Vous avez écouté cette piste %n fois.Vous avez écouté cette piste %n fois. - + You've never listened to this track before. Vous n'avez encore jamais écouté cette piste. - + You first listened to it on %1. Vous l'avez écouté pour la première fois le %1. - + You've listened to %1 %n time(s). Vous avez écouté %1 %n fois.Vous avez écouté %1 %n fois. - + You've never listened to %1 before. Vous n'avez encore jamais écouté %1. @@ -3285,7 +3285,7 @@ saisissez le numéro PIN ici : TrackView - + Sorry, your filter '%1' did not match any results. Désolé, votre filtre '%1' ne correspond à aucun résultat @@ -3447,27 +3447,27 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Collections regroupant toutes celles de vos amis en ligne - + All available albums Tous les albums disponibles - + Recently Played Tracks Derniers titres joués - + Recently played tracks from all your friends Derniers titres joués par vos amis @@ -3490,7 +3490,7 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env Joués récemment - + No recently created playlists in your network. Pas de liste de lecture créée récemment sur votre réseau. diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 0db23252a..ca558174e 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -133,7 +133,7 @@ connect and stream from you? - + Other Albums by %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. このコレクションは現在空です。 - + Sorry, your filter '%1' did not match any results. @@ -990,12 +990,12 @@ other: %n年前 - + Show Queue - + Hide Queue @@ -1214,17 +1214,17 @@ other: %n年前 - + New Additions - + My recent activity - + Recent activity from %1 @@ -1617,12 +1617,12 @@ other: %n年前 Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1732,12 +1732,12 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1992,32 +1992,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -2075,17 +2075,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2547,27 +2547,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3246,27 +3246,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3274,7 +3274,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3431,27 +3431,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3474,7 +3474,7 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index c8671732d..1e2c68330 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -133,7 +133,7 @@ connect and stream from you? Inne albumy artysty - + Other Albums by %1 Inne albumy %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Po zeskanowaniu swojej kolekcji muzycznej w tym miejscu znajdziesz ostatnio dodane albumy. - + This collection doesn't have any recent albums. Ta kolekcja nie zawiera żadnych nowo dodanych albumów. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Po zeskanowaniu swojej kolekcji muzycznej utwory znajdziesz w tym miejscu. - + This collection is currently empty. Ta kolekcja jest aktualnie pusta. - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie pasuje do żadnych wyników. @@ -988,12 +988,12 @@ connect and stream from you? - + Show Queue Pokaż Kolejkę - + Hide Queue Ukryj Kolejkę @@ -1212,17 +1212,17 @@ connect and stream from you? Ostatnio Odtwarzane Utwory - + New Additions Nowo dodane - + My recent activity Moja ostatnia aktywność - + Recent activity from %1 Ostatnia aktywność %1 @@ -1619,12 +1619,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1734,12 +1734,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1994,32 +1994,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Najbardziej Lubiane Utwory - + Your loved tracks Twoje ulubione utwory - + %1's loved tracks Ulubione utwory %1 - + The most loved tracks from all your friends Najbardziej lubiane utwory wszystkich twoich znajomych - + All of your loved tracks Wszystkie twoje ulubione utwory - + All of %1's loved tracks Wszystkie ulubione utwory %1 @@ -2079,17 +2079,17 @@ Proszę zmienić filtry lub spróbować ponownie. Tomahawk::DynamicView - + Add some filters above to seed this station! Dodaj powyżej trochę filtrów, a Tomahawk utworzy stację z podobną muzyką! - + Press Generate to get started! Naciśnij Generuj aby zacząć! - + Add some filters above, and press Generate to get started! Dodaj powyżej trochę filtrów i naciśnij Generuj aby zacząć! @@ -2551,27 +2551,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3251,27 +3251,27 @@ wprowadź pokazany numer PIN tutaj: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3279,7 +3279,7 @@ wprowadź pokazany numer PIN tutaj: TrackView - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie dopasował żadnych wyników. @@ -3441,27 +3441,27 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl ViewManager - + SuperCollection SuperKolekcja - + Combined libraries of all your online friends Połączone biblioteki wszystkich twoich znajomych online - + All available albums Wszystkie dostępne albumy - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3484,7 +3484,7 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl Ostatnio Odtworzone Utwory - + No recently created playlists in your network. Brak ostatnio utworzonych list w twojej sieci. diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 69e7a7a5e..8ccb5af8c 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -133,7 +133,7 @@ connect and stream from you? Outros álbuns do artista - + Other Albums by %1 Outros álbuns por %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Depois que você escanear a sua biblioteca musical você encontrará aqui o último álbum adicionado. - + This collection doesn't have any recent albums. Essa biblioteca não tem nenhum álbum recente. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Depois que você escanear a sua biblioteca musical você encontrará aqui as suas faixas. - + This collection is currently empty. Essa biblioteca está vazia. - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -988,12 +988,12 @@ connect and stream from you? - + Show Queue Mostrar fila - + Hide Queue Ocultar fila @@ -1212,17 +1212,17 @@ connect and stream from you? Faixas reproduzidas recentemente - + New Additions Novas adições - + My recent activity Minha atividade recentes - + Recent activity from %1 Atividade recente de %1 @@ -1618,12 +1618,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1733,12 +1733,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1993,32 +1993,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Faixas favoritas - + Your loved tracks Suas faixas favoritas - + %1's loved tracks Faixas favoritas de %1 - + The most loved tracks from all your friends As faixas preferidas dos seus amigos - + All of your loved tracks Todas as suas faixas preferidas - + All of %1's loved tracks Todas as faixas preferidas de %1 @@ -2078,17 +2078,17 @@ Por favor, mude os filtros ou tente novamente. Tomahawk::DynamicView - + Add some filters above to seed this station! Adicione alguns filtros para alimentar essa estação! - + Press Generate to get started! Precione Criar para iniciar! - + Add some filters above, and press Generate to get started! Adicione alguns filtros acima e precione Criar para iniciar! @@ -2550,27 +2550,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3250,27 +3250,27 @@ colocar o número PIN mostrado aqui: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3278,7 +3278,7 @@ colocar o número PIN mostrado aqui: TrackView - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -3440,27 +3440,27 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Todos os álbuns disponíveis - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3483,7 +3483,7 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment Faixas reproduzidas recentemente - + No recently created playlists in your network. Nenhuma lista de reprodução criada recentemente na sua rede. diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index f5c0bbecf..17b8b0d15 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -134,7 +134,7 @@ connect and stream from you? Другие альбомы артиста - + Other Albums by %1 Другие альбомы %1 @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. После сканирования вашей музыкальной коллекции вы найдете свой альбомы тут. - + This collection doesn't have any recent albums. Эта коллекция не имеет последних альбомов. @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. После сканирования вашей музыкальной коллекции вы найдете свои песни тут. - + This collection is currently empty. Коллекция пуста. - + Sorry, your filter '%1' did not match any results. К сожалению, '%1' фильтр не найдено ни одного результата. @@ -990,12 +990,12 @@ connect and stream from you? - + Show Queue Показать Очередь - + Hide Queue Скрыть Очередь @@ -1214,17 +1214,17 @@ connect and stream from you? Последние проигрыные песни - + New Additions Последние добавленые - + My recent activity Моя последняя активность - + Recent activity from %1 Последняя активно %1 @@ -1617,12 +1617,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1732,12 +1732,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -1995,32 +1995,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Топ любимых песен - + Your loved tracks Ваши любимые песни - + %1's loved tracks %1's любимая песня - + The most loved tracks from all your friends Самые любимые песни от всех ваших друзей - + All of your loved tracks Все любимые песни - + All of %1's loved tracks Все от %1 любимые песни @@ -2080,17 +2080,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Добавить некоторые фильтры, чтобы увидеть эту станцию​​! - + Press Generate to get started! Нажмите кнопку Создать, чтобы начать! - + Add some filters above, and press Generate to get started! Добавьте несколько фильтров выше, а затем нажмите Создать, чтобы начать! @@ -2552,27 +2552,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3251,27 +3251,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3279,7 +3279,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Ваш поиск '%1' недал результатов. @@ -3440,27 +3440,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Общая коллекция - + Combined libraries of all your online friends Комбинированные библиотек всех ваших друзей онлайн - + All available albums Доступные альбомы - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3483,7 +3483,7 @@ You can re-send a sync message at any time simply by sending another tweet using Последние Воспроизводимые Песни - + No recently created playlists in your network. Нет списков, созданных в последнее время в вашей сети. diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 6882e826c..bc7e74b33 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -133,7 +133,7 @@ connect and stream from you? Andra album av artisten - + Other Albums by %1 Andra album av %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda album här. - + This collection doesn't have any recent albums. Den här samlingen inga nya album. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda låtar här. - + This collection is currently empty. Denna samling är tom. - + Sorry, your filter '%1' did not match any results. Tyvärr, ditt filter "%1" matchade inte några resultat. @@ -989,12 +989,12 @@ connect and stream from you? - + Show Queue Visa kö - + Hide Queue Dölj kö @@ -1213,17 +1213,17 @@ connect and stream from you? Senaste spelade spår - + New Additions Nya tillägg - + My recent activity Min senaste aktivitet - + Recent activity from %1 Senaste aktivitet från %1 @@ -1616,12 +1616,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1731,12 +1731,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1991,32 +1991,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Mest älskade spår - + Your loved tracks Dina älskade spår - + %1's loved tracks Älskade spår för %1 - + The most loved tracks from all your friends De mest älskade spåren från alla dina vänner - + All of your loved tracks Alla dina älskade spår - + All of %1's loved tracks Alla spår som %1 älskar @@ -2074,17 +2074,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2546,27 +2546,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3245,27 +3245,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3273,7 +3273,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3430,27 +3430,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Alla tillgängliga album - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3473,7 +3473,7 @@ You can re-send a sync message at any time simply by sending another tweet using Senaste spelade spår - + No recently created playlists in your network. Inga skapade spellistor i ditt nätverk på sistone. diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index db27ad047..6772683eb 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -133,7 +133,7 @@ connect and stream from you? Sanatçının Diğer Albümleri - + Other Albums by %1 Diğer %1 Albümleri @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Müzik koleksiyonunuzu taradıktan sonra en son eklenen albümleri burada bulacaksınız. - + This collection doesn't have any recent albums. Bu koleksiyonda en son eklenen bir albüm yok. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Müzik koleksiyonunuzu taradıktan parçalarınız tam burada bulacaksınız. - + This collection is currently empty. Bu koleksiyon şu anda boş. - + Sorry, your filter '%1' did not match any results. Üzgünüm, '%1' filtresi hiçbir sonuç getirmedi. @@ -988,12 +988,12 @@ connect and stream from you? - + Show Queue - + Hide Queue @@ -1212,17 +1212,17 @@ connect and stream from you? - + New Additions - + My recent activity - + Recent activity from %1 @@ -1615,12 +1615,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1730,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1990,32 +1990,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -2073,17 +2073,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2545,27 +2545,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3244,27 +3244,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3272,7 +3272,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3429,27 +3429,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3472,7 +3472,7 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 3a730a7cf..c456c80c0 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -133,7 +133,7 @@ connect and stream from you? 艺人的其他专辑 - + Other Albums by %1 %1 的其他专辑 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. 此收藏目前为空 - + Sorry, your filter '%1' did not match any results. 抱歉,你的过滤条件 '%1' 未匹配任何结果 @@ -988,12 +988,12 @@ connect and stream from you? - + Show Queue - + Hide Queue @@ -1212,17 +1212,17 @@ connect and stream from you? - + New Additions - + My recent activity - + Recent activity from %1 @@ -1615,12 +1615,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1730,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1990,32 +1990,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -2073,17 +2073,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2545,27 +2545,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3244,27 +3244,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3272,7 +3272,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3429,27 +3429,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3472,7 +3472,7 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index eba246551..555b1bdf0 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -133,7 +133,7 @@ connect and stream from you? 列出演出者的其他專輯 - + Other Albums by %1 列出所有其他專輯,依 %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. 當您掃描您的音樂收藏,您會發現您的最新專輯添加在這裡。 - + This collection doesn't have any recent albums. 這個收藏沒有任何最新專輯。 @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. 當您掃描您的音樂收藏,您將在這裡找到您的曲目。 - + This collection is currently empty. 目前這個收藏是空的。 - + Sorry, your filter '%1' did not match any results. @@ -988,12 +988,12 @@ connect and stream from you? - + Show Queue 顯示佇列 - + Hide Queue 隱藏佇列 @@ -1212,17 +1212,17 @@ connect and stream from you? 最近播放的曲目 - + New Additions 新增 - + My recent activity 我的近期活動 - + Recent activity from %1 @@ -1615,12 +1615,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1730,12 +1730,12 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Stop syncing with Spotify @@ -1990,32 +1990,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends 在您所有的朋友中,最受喜愛的曲目 - + All of your loved tracks - + All of %1's loved tracks @@ -2073,17 +2073,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2545,27 +2545,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -3244,27 +3244,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3272,7 +3272,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3430,27 +3430,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection 超級收藏 - + Combined libraries of all your online friends 聯合您所有線上朋友的音樂庫 - + All available albums 所有現有專輯 - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3473,7 +3473,7 @@ You can re-send a sync message at any time simply by sending another tweet using 最近播放的曲目 - + No recently created playlists in your network. 沒有最近建立的播放清單在您的網路。 From 052093f1eabc7217adb1128e6d17cd344e401e69 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 24 May 2012 21:05:35 -0400 Subject: [PATCH 068/433] Try out some fading --- .../playlist/AlbumItemDelegate.cpp | 119 +++++++++++++----- src/libtomahawk/playlist/AlbumItemDelegate.h | 12 +- src/libtomahawk/utils/PixmapDelegateFader.cpp | 4 +- 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index 980454817..a01abac36 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "Artist.h" #include "Query.h" @@ -42,6 +43,10 @@ #include "widgets/ImageButton.h" #include "utils/Logger.h" +namespace { + static const int FADE_DURATION = 90; +}; + AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) @@ -50,7 +55,7 @@ AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel { if ( m_view && m_view->metaObject()->indexOfSignal( "modelChanged()" ) > -1 ) connect( m_view, SIGNAL( modelChanged() ), this, SLOT( modelChanged() ) ); - + connect( m_view, SIGNAL( scrolledContents( int, int ) ), SLOT( onScrolled( int, int ) ) ); } @@ -121,33 +126,28 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QPixmap cover = fader->currentPixmap(); - if ( false && option.state & QStyle::State_Selected ) - { -#if defined(Q_WS_MAC) || defined(Q_WS_WIN) - painter->save(); - - QPainterPath border; - border.addRoundedRect( r.adjusted( -2, -2, 2, 2 ), 3, 3 ); - QPen borderPen( QColor( 86, 170, 243 ) ); - borderPen.setWidth( 5 ); - painter->setPen( borderPen ); - painter->drawPath( border ); - - painter->restore(); -#else - opt.palette.setColor( QPalette::Text, opt.palette.color( QPalette::HighlightedText ) ); -#endif - } - painter->drawPixmap( r, cover ); - if ( m_hoverIndex == index ) + + qreal opacity = -1.; + if ( m_hoverFaders.contains( index ) ) + { + const qreal pct = ( m_hoverFaders[ index ]->currentFrame() / 100. ); + opacity = 0.15 - pct * 0.15; + } + else if ( m_hoverIndex != index ) + { + opacity = 0.15; + } + + + if ( opacity > -1. ) { painter->save(); - painter->setPen( QColor( 33, 33, 33 ) ); - painter->setBrush( QColor( 33, 33, 33 ) ); - painter->setOpacity( 0.5 ); + painter->setPen( QColor( 240, 240, 240 ) ); + painter->setBrush( QColor( 240, 240, 240 ) ); + painter->setOpacity( opacity ); painter->drawRect( r ); painter->restore(); @@ -236,12 +236,12 @@ AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) spinner->installEventFilter( this ); m_spinner[ index ] = spinner; - + PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); if ( item ) { _detail::Closure* closure; - + closure = NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), const_cast(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); @@ -276,8 +276,8 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const bool hoveringArtist = false; if ( m_artistNameRects.contains( index ) ) { - QRect artistNameRect = m_artistNameRects[ index ]; - QMouseEvent* ev = static_cast< QMouseEvent* >( event ); + const QRect artistNameRect = m_artistNameRects[ index ]; + const QMouseEvent* ev = static_cast< QMouseEvent* >( event ); hoveringArtist = artistNameRect.contains( ev->pos() ); } @@ -288,7 +288,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const if ( index != idx ) m_playButton.take( idx )->deleteLater(); } - + if ( !m_playButton.contains( index ) && !m_spinner.contains( index ) && !m_pauseButton.contains( index ) ) { foreach ( ImageButton* button, m_playButton ) @@ -304,7 +304,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const button->setFocusPolicy( Qt::NoFocus ); button->installEventFilter( this ); button->show(); - + NewClosure( button, SIGNAL( clicked( bool ) ), const_cast(this), SLOT( onPlayClicked( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); @@ -325,11 +325,32 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const if ( m_hoverIndex != index ) { + if ( m_hoverIndex.isValid() ) + { + QTimeLine* fadeOut = createTimeline( QTimeLine::Backward ); + _detail::Closure* c = NewClosure( fadeOut, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); + c->setAutoDelete( false ); + c = NewClosure( fadeOut, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); + c->setAutoDelete( false ); + m_hoverFaders[ m_hoverIndex ] = fadeOut; + fadeOut->start(); + } + emit updateIndex( m_hoverIndex ); m_hoverIndex = index; + + QTimeLine* fadeIn = createTimeline( QTimeLine::Forward ); + _detail::Closure* c = NewClosure( fadeIn, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + c->setAutoDelete( false ); + c = NewClosure( fadeIn, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + c->setAutoDelete( false ); + + m_hoverFaders[ index ] = fadeIn; + fadeIn->start(); + emit updateIndex( index ); } - + event->accept(); return true; } @@ -443,7 +464,7 @@ AlbumItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) if ( AudioEngine::instance()->currentTrackPlaylist() != item->artist()->playlistInterface( Tomahawk::Mixed ) ) finished = true; } - + if ( finished ) { if ( m_pauseButton.contains( index ) ) @@ -468,7 +489,7 @@ AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) delete widget; } m_spinner.clear(); - + ImageButton* button = new ImageButton( m_view ); button->setPixmap( RESPATH "images/pause-rest.png" ); button->setPixmap( RESPATH "images/pause-pressed.png", QIcon::Off, QIcon::Active ); @@ -478,13 +499,45 @@ AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) button->setFocusPolicy( Qt::NoFocus ); button->installEventFilter( this ); button->show(); - + connect( button, SIGNAL( clicked( bool ) ), AudioEngine::instance(), SLOT( playPause() ) ); m_pauseButton[ index ] = button; } +void +AlbumItemDelegate::fadingFrameChanged( const QPersistentModelIndex& idx ) +{ + emit updateIndex( idx ); +} + + +void +AlbumItemDelegate::fadingFrameFinished( const QPersistentModelIndex& idx ) +{ + if ( m_hoverFaders.contains( idx ) ) + { + m_hoverFaders.take( idx )->deleteLater(); + emit updateIndex( idx ); + } +} + + +QTimeLine* +AlbumItemDelegate::createTimeline( QTimeLine::Direction direction ) +{ + QTimeLine* timeline = new QTimeLine( FADE_DURATION, this ); + timeline->setDirection( direction ); + timeline->setCurveShape( QTimeLine::LinearCurve ); + timeline->setUpdateInterval( 30 ); + timeline->setStartFrame( 0 ); + timeline->setEndFrame( 100 ); + + return timeline; +} + + bool AlbumItemDelegate::eventFilter( QObject* obj, QEvent* event ) { diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.h b/src/libtomahawk/playlist/AlbumItemDelegate.h index 0715e781d..1f38d76a9 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.h +++ b/src/libtomahawk/playlist/AlbumItemDelegate.h @@ -21,9 +21,11 @@ #define ALBUMITEMDELEGATE_H #include +#include #include "DllMacro.h" +class QTimeLine; namespace Tomahawk { class PixmapDelegateFader; } @@ -52,15 +54,19 @@ signals: private slots: void modelChanged(); void doUpdateIndex( const QPersistentModelIndex& idx ); - + void onScrolled( int dx, int dy ); void onPlaybackStarted( const QPersistentModelIndex& index ); void onPlaybackFinished(); - + void onPlayClicked( const QPersistentModelIndex& index ); void onPlaylistChanged( const QPersistentModelIndex& index ); + void fadingFrameChanged( const QPersistentModelIndex& ); + void fadingFrameFinished( const QPersistentModelIndex& ); private: + QTimeLine* createTimeline( QTimeLine::Direction direction ); + QAbstractItemView* m_view; AlbumProxyModel* m_model; @@ -75,6 +81,8 @@ private: mutable QHash< QPersistentModelIndex, QWidget* > m_spinner; mutable QHash< QPersistentModelIndex, ImageButton* > m_playButton; mutable QHash< QPersistentModelIndex, ImageButton* > m_pauseButton; + + mutable QHash< QPersistentModelIndex, QTimeLine* > m_hoverFaders; }; #endif // ALBUMITEMDELEGATE_H diff --git a/src/libtomahawk/utils/PixmapDelegateFader.cpp b/src/libtomahawk/utils/PixmapDelegateFader.cpp index 7fe2f5dab..867a4d26a 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.cpp +++ b/src/libtomahawk/utils/PixmapDelegateFader.cpp @@ -29,8 +29,6 @@ using namespace Tomahawk; -#define COVER_FADEIN 1000 - QWeakPointer< TomahawkUtils::SharedTimeLine > PixmapDelegateFader::s_stlInstance = QWeakPointer< TomahawkUtils::SharedTimeLine >(); @@ -126,7 +124,7 @@ void PixmapDelegateFader::setSize( const QSize& size ) { m_size = size; - + if ( m_defaultImage ) { // No cover loaded yet, use default and don't fade in From 9294b73c5744f914585d58c536925df34105049c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 24 May 2012 21:54:41 -0400 Subject: [PATCH 069/433] Invert --- src/libtomahawk/playlist/AlbumItemDelegate.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index a01abac36..c05ee89a4 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -44,7 +44,7 @@ #include "utils/Logger.h" namespace { - static const int FADE_DURATION = 90; + static const int FADE_DURATION = 75; }; @@ -133,11 +133,11 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, if ( m_hoverFaders.contains( index ) ) { const qreal pct = ( m_hoverFaders[ index ]->currentFrame() / 100. ); - opacity = 0.15 - pct * 0.15; + opacity = 0.35 - pct * 0.35; } - else if ( m_hoverIndex != index ) + else if ( m_hoverIndex == index ) { - opacity = 0.15; + opacity = 0.35; } @@ -145,8 +145,8 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, { painter->save(); - painter->setPen( QColor( 240, 240, 240 ) ); - painter->setBrush( QColor( 240, 240, 240 ) ); + painter->setPen( QColor( 33, 33, 33 ) ); + painter->setBrush( QColor( 33, 33, 33 ) ); painter->setOpacity( opacity ); painter->drawRect( r ); @@ -327,7 +327,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const { if ( m_hoverIndex.isValid() ) { - QTimeLine* fadeOut = createTimeline( QTimeLine::Backward ); + QTimeLine* fadeOut = createTimeline( QTimeLine::Forward ); _detail::Closure* c = NewClosure( fadeOut, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); c->setAutoDelete( false ); c = NewClosure( fadeOut, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); @@ -339,7 +339,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const emit updateIndex( m_hoverIndex ); m_hoverIndex = index; - QTimeLine* fadeIn = createTimeline( QTimeLine::Forward ); + QTimeLine* fadeIn = createTimeline( QTimeLine::Backward ); _detail::Closure* c = NewClosure( fadeIn, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); c->setAutoDelete( false ); c = NewClosure( fadeIn, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); From 677944d403e0eed43f764adb2277777dbf32de18 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 24 May 2012 20:59:17 -0400 Subject: [PATCH 070/433] Discogs infoplugin, only albums contents atm. --- src/infoplugins/generic/CMakeLists.txt | 1 + .../generic/discogs/DiscogsPlugin.cpp | 189 ++++++++++++++++++ .../generic/discogs/DiscogsPlugin.h | 63 ++++++ .../generic/musicbrainz/MusicBrainzPlugin.cpp | 26 --- .../generic/musicbrainz/MusicBrainzPlugin.h | 3 - 5 files changed, 253 insertions(+), 29 deletions(-) create mode 100644 src/infoplugins/generic/discogs/DiscogsPlugin.cpp create mode 100644 src/infoplugins/generic/discogs/DiscogsPlugin.h diff --git a/src/infoplugins/generic/CMakeLists.txt b/src/infoplugins/generic/CMakeLists.txt index 7473744f1..c077e1e77 100644 --- a/src/infoplugins/generic/CMakeLists.txt +++ b/src/infoplugins/generic/CMakeLists.txt @@ -9,6 +9,7 @@ list(APPEND simple_plugins MusixMatch MusicBrainz Rovi + Discogs ) foreach(simple_plugin ${simple_plugins}) diff --git a/src/infoplugins/generic/discogs/DiscogsPlugin.cpp b/src/infoplugins/generic/discogs/DiscogsPlugin.cpp new file mode 100644 index 000000000..f4dc88652 --- /dev/null +++ b/src/infoplugins/generic/discogs/DiscogsPlugin.cpp @@ -0,0 +1,189 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "DiscogsPlugin.h" + +#include +#include +#include + +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" +#include "utils/Closure.h" +#include + +using namespace Tomahawk::InfoSystem; + + +DiscogsPlugin::DiscogsPlugin() + : InfoPlugin() +{ + qDebug() << Q_FUNC_INFO; + m_supportedGetTypes << Tomahawk::InfoSystem::InfoAlbumSongs; +} + + +DiscogsPlugin::~DiscogsPlugin() {} + + +void +DiscogsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) +{ + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + { + emit info( requestData, QVariant() ); + return; + } + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + if ( !hash.contains( "artist" ) || !hash.contains( "album" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + switch ( requestData.type ) + { + case InfoAlbumSongs: + { + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria["artist"] = hash["artist"]; + criteria["album"] = hash["album"]; + + emit getCachedInfo( criteria, 2419200000, requestData ); + + break; + } + + default: + { + Q_ASSERT( false ); + break; + } + } +} + + +void +DiscogsPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ) +{ + switch ( requestData.type ) + { + case InfoAlbumSongs: + { + QString requestString( "http://api.discogs.com/database/search" ); + QUrl url( requestString ); + url.addQueryItem( "type", "release" ); + url.addQueryItem( "release_title", criteria[ "album" ] ); + url.addQueryItem( "artist", criteria[ "artist" ] ); + QNetworkRequest req( url ); + req.setRawHeader( "User-Agent", "TomahawkPlayer/1.0 +http://tomahawk-player.org" ); + QNetworkReply* reply = TomahawkUtils::nam()->get( req ); + + NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumSearchSlot( Tomahawk::InfoSystem::InfoRequestData, QNetworkReply* ) ), requestData, reply ); + break; + } + + default: + { + Q_ASSERT( false ); + break; + } + } +} + + +void +DiscogsPlugin::albumSearchSlot( const InfoRequestData &requestData, QNetworkReply *reply ) +{ + QJson::Parser p; + QVariantMap results = p.parse( reply ).toMap(); + + if ( !results.contains( "results" ) || results.value( "results" ).toList().isEmpty() ) + { + emit info( requestData, QVariant() ); + return; + } + + const QVariantMap result = results.value( "results" ).toList().first().toMap(); + if ( !result.contains( "id" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + const int id = result.value( "id" ).toInt(); + QUrl url( QString( "http://api.discogs.com/release/%1" ).arg( id ) ); + QNetworkRequest req( url ); + req.setRawHeader( "User-Agent", "TomahawkPlayer/1.0 +http://tomahawk-player.org" ); + + QNetworkReply* reply2 = TomahawkUtils::nam()->get( req ); + NewClosure( reply2, SIGNAL( finished() ), this, SLOT( albumInfoSlot( Tomahawk::InfoSystem::InfoRequestData, QNetworkReply* ) ), requestData, reply2 ); +} + + +void +DiscogsPlugin::albumInfoSlot( const InfoRequestData& requestData, QNetworkReply* reply ) +{ + QJson::Parser p; + QVariantMap results = p.parse( reply ).toMap(); + + if ( !results.contains( "resp" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + const QVariantMap resp = results[ "resp" ].toMap(); + if ( !resp.contains( "release" ) ) + { + emit info( requestData, QVariant() ); + return; + } + + const QVariantMap release = resp[ "release" ].toMap(); + if ( !release.contains( "tracklist" ) || release[ "tracklist" ].toList().isEmpty() ) + { + emit info( requestData, QVariant() ); + return; + } + + QStringList trackNameList; + foreach ( const QVariant& v, release[ "tracklist" ].toList() ) + { + const QVariantMap track = v.toMap(); + if ( track.contains( "title" ) ) + trackNameList << track[ "title" ].toString(); + } + + QVariantMap returnedData; + returnedData["tracks"] = trackNameList; + + emit info( requestData, returnedData ); + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria["artist"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["artist"]; + criteria["album"] = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>()["album"]; + + emit updateCache( criteria, 0, requestData.type, returnedData ); +} + + + +Q_EXPORT_PLUGIN2( Tomahawk::InfoSystem::InfoPlugin, Tomahawk::InfoSystem::DiscogsPlugin ) diff --git a/src/infoplugins/generic/discogs/DiscogsPlugin.h b/src/infoplugins/generic/discogs/DiscogsPlugin.h new file mode 100644 index 000000000..654fe7e52 --- /dev/null +++ b/src/infoplugins/generic/discogs/DiscogsPlugin.h @@ -0,0 +1,63 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef DISCOGS_PLUGIN_H +#define DISCOGS_PLUGIN_H + +#include "Typedefs.h" +#include "infosystem/InfoSystem.h" +#include "infosystem/InfoSystemWorker.h" +#include "infoplugins/InfoPluginDllMacro.h" + +class QNetworkReply; + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +class INFOPLUGINDLLEXPORT DiscogsPlugin : public InfoPlugin +{ + Q_OBJECT + Q_INTERFACES( Tomahawk::InfoSystem::InfoPlugin ) + +public: + DiscogsPlugin(); + virtual ~DiscogsPlugin(); + +protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ); + + virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData ) {} +private slots: + void albumSearchSlot( const Tomahawk::InfoSystem::InfoRequestData& , QNetworkReply* ); + void albumInfoSlot( const Tomahawk::InfoSystem::InfoRequestData& , QNetworkReply* ); + +private: + bool isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData ); +}; + +} + +} + +Q_DECLARE_METATYPE( QNetworkReply* ) +#endif diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp index 625a527ce..3a52e3e52 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.cpp @@ -129,32 +129,6 @@ MusicBrainzPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requ } -bool -MusicBrainzPlugin::isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData ) -{ - if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QVariantMap >() ) - { - emit info( requestData, QVariant() ); - qDebug() << Q_FUNC_INFO << "Data null, invalid, or can't convert"; - return false; - } - QVariantMap hash = requestData.input.value< QVariantMap >(); - if ( hash[ "trackName" ].toString().isEmpty() ) - { - emit info( requestData, QVariant() ); - qDebug() << Q_FUNC_INFO << "Track name is empty"; - return false; - } - if ( hash[ "artistName" ].toString().isEmpty() ) - { - emit info( requestData, QVariant() ); - qDebug() << Q_FUNC_INFO << "No artist name found"; - return false; - } - return true; -} - - void MusicBrainzPlugin::artistSearchSlot() { diff --git a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h index 21043caeb..57ca6bc99 100644 --- a/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h +++ b/src/infoplugins/generic/musicbrainz/MusicBrainzPlugin.h @@ -59,9 +59,6 @@ private slots: void albumFoundSlot(); void tracksFoundSlot(); - -private: - bool isValidTrackData( Tomahawk::InfoSystem::InfoRequestData requestData ); }; } From 3b5f48926c18ebf25aa70cac11d75cd3c6b16f25 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 25 May 2012 05:52:08 +0200 Subject: [PATCH 071/433] * Remove gloox support. XmppBot will need to be ported but was broken by now, anyway. --- CMakeModules/FindGloox.cmake | 23 ----------------------- src/CMakeLists.txt | 8 -------- src/Config.h.in | 1 - src/TomahawkApp.cpp | 9 --------- 4 files changed, 41 deletions(-) delete mode 100644 CMakeModules/FindGloox.cmake diff --git a/CMakeModules/FindGloox.cmake b/CMakeModules/FindGloox.cmake deleted file mode 100644 index ccdbdcfbf..000000000 --- a/CMakeModules/FindGloox.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# - Try to find GLOOX -# Find GLOOX headers, libraries and the answer to all questions. -# -# GLOOX_FOUND True if gloox got found -# GLOOX_INCLUDE_DIR Location of gloox headers -# GLOOX_LIBRARIES List of libaries to use gloox -# -# Copyright (c) 2009 Nigmatullin Ruslan -# -# Redistribution and use is allowed according to the terms of the New -# BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. -# - -FIND_PATH( GLOOX_INCLUDE_DIR "gloox/gloox.h" ) -FIND_LIBRARY( GLOOX_LIBRARIES gloox ) - -if( GLOOX_LIBRARIES AND GLOOX_INCLUDE_DIR ) - message( STATUS "Found gloox: ${GLOOX_LIBRARIES}" ) - set( GLOOX_FOUND 1 ) -else( GLOOX_LIBRARIES AND GLOOX_INCLUDE_DIR ) - message( STATUS "Could NOT find gloox" ) -endif( GLOOX_LIBRARIES AND GLOOX_INCLUDE_DIR ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78aefef0d..07e594c76 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -154,11 +154,6 @@ IF( APPLE ) SET( tomahawkSources ${tomahawkSources} mac/TomahawkApp_Mac.mm mac/MacShortcutHandler.cpp ) ENDIF( APPLE ) -IF(GLOOX_FOUND) - INCLUDE_DIRECTORIES( ${GLOOX_INCLUDE_DIR} ) - SET( tomahawkSources ${tomahawkSources} xmppbot/XmppBot.cpp ) -ENDIF(GLOOX_FOUND) - ADD_SUBDIRECTORY( accounts ) ADD_SUBDIRECTORY( infoplugins ) @@ -207,9 +202,6 @@ SET(LINK_LIBRARIES "") IF(LIBLASTFM_FOUND) SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_lastfm2 ) ENDIF(LIBLASTFM_FOUND) -IF(GLOOX_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${GLOOX_LIBRARIES} ) -ENDIF(GLOOX_FOUND) IF(QCA2_FOUND) SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) ENDIF(QCA2_FOUND) diff --git a/src/Config.h.in b/src/Config.h.in index 87ec9b48d..c6172e0d9 100644 --- a/src/Config.h.in +++ b/src/Config.h.in @@ -21,7 +21,6 @@ #cmakedefine WITH_CRASHREPORTER #cmakedefine LIBLASTFM_FOUND -#cmakedefine GLOOX_FOUND #cmakedefine QCA2_FOUND #endif // CONFIG_H_IN diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 21dd156ad..796b4392a 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -83,11 +83,6 @@ #include #endif -// should go to a plugin actually -#ifdef GLOOX_FOUND - #include "xmppbot/XmppBot.h" -#endif - #ifdef Q_WS_MAC #include "mac/MacShortcutHandler.h" @@ -593,10 +588,6 @@ TomahawkApp::initSIP() //FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings if ( !arguments().contains( "--nosip" ) ) { -#ifdef GLOOX_FOUND - m_xmppBot = QWeakPointer( new XMPPBot( this ) ); -#endif - tDebug( LOGINFO ) << "Connecting SIP classes"; Accounts::AccountManager::instance()->initSIP(); } From 81949ee0a0a61afdd1e880d7be5d826cb41c02e5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 25 May 2012 06:05:02 +0200 Subject: [PATCH 072/433] * Support arabic translation. --- lang/tomahawk_i18n.qrc | 1 + 1 file changed, 1 insertion(+) diff --git a/lang/tomahawk_i18n.qrc b/lang/tomahawk_i18n.qrc index 575f8b9e1..f01815d68 100644 --- a/lang/tomahawk_i18n.qrc +++ b/lang/tomahawk_i18n.qrc @@ -10,5 +10,6 @@ tomahawk_es.qm tomahawk_sv.qm tomahawk_ja.qm +tomahawk_ar.qm From 63843416cf7d5b277cfaa18993b48992abdf6e72 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 25 May 2012 06:40:23 +0200 Subject: [PATCH 073/433] * Fixed about dialog translation. --- src/TomahawkWindow.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 355ca6041..3a95b1bcb 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -847,8 +847,13 @@ TomahawkWindow::showAboutTomahawk() .arg( TomahawkUtils::appFriendlyVersion() ); #endif - desc = tr( "Copyright 2010 - 2012
    Christian Muehlhaeuser <muesli@tomahawk-player.org>

    " - "Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Michael Zanetti, Harald Sitter and Steve Robertson" ); + const QString copyright( tr( "Copyright 2010 - 2012" ) ); + const QString thanksto( tr( "Thanks to:" ) ); + + desc = QString( "%1
    Christian Muehlhaeuser <muesli@tomahawk-player.org>

    " + "%2 Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Syd Lawrence, Michael Zanetti, Harald Sitter, Steve Robertson" ) + .arg( copyright ) + .arg( thanksto ); QMessageBox::about( this, tr( "About Tomahawk" ), head + desc ); } From 2af0d9a027751b87d38734ac4e8ed96fc40b3621 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Fri, 25 May 2012 04:43:20 +0000 Subject: [PATCH 074/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 265 +++++++++++++++++++++-------------------- lang/tomahawk_bg.ts | 2 +- lang/tomahawk_ca.ts | 2 +- lang/tomahawk_de.ts | 2 +- lang/tomahawk_en.ts | 2 +- lang/tomahawk_es.ts | 2 +- lang/tomahawk_fr.ts | 2 +- lang/tomahawk_ja.ts | 2 +- lang/tomahawk_pl.ts | 2 +- lang/tomahawk_pt_BR.ts | 2 +- lang/tomahawk_ru.ts | 2 +- lang/tomahawk_sv.ts | 2 +- lang/tomahawk_tr.ts | 2 +- lang/tomahawk_zh_CN.ts | 2 +- lang/tomahawk_zh_TW.ts | 2 +- 15 files changed, 153 insertions(+), 140 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index edbfcfe26..93fe9380b 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -209,7 +209,7 @@ connect and stream from you? Sorry, your filter '%1' did not match any results. - نتأسف، نظام البحث لم يجد شيئا تحت عنوان '%1'. + نتأسف، نظام الترشيح لم يجد شيئا تحت عنوان '%1'.
    @@ -385,7 +385,7 @@ connect and stream from you? <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">نتأسف!</span>&nbsp;توماهوك تحطم. يرجى أن تخبرنا عن ذلك! لقد أنشئ توماهوك تقرير عن الخطأ نيابة عنك لمساعدتنا في تحسين استقرار البرنامج في المستقبل. يمكنك إرسال هذا التقرير الأن مباشرة لمطوري توماهوك.</p></body></html> @@ -507,7 +507,7 @@ connect and stream from you? Filter... - فلتر... + مرشح... @@ -682,7 +682,7 @@ connect and stream from you? Composer - + مؤلف @@ -707,7 +707,7 @@ connect and stream from you? Age - + عمر @@ -766,7 +766,7 @@ connect and stream from you? A playlist by %1, created %2 - + قائمة أغاني من قبل %1, أنشئت %2 @@ -1114,17 +1114,17 @@ connect and stream from you? Twitter - + تويتر (Twitter) Cover - غطاء + غلاف TextLabel - + TextLabel @@ -1134,7 +1134,7 @@ connect and stream from you? Listening to "%1" by %2 on "%3" and loving it! %4 - + يتم الاستماع إلى "%1" من قبل %2 على "%3" وقد أحبها! %4 @@ -1420,7 +1420,7 @@ connect and stream from you? High Quality Streams - + جودة عالية في الأغاني المحملة @@ -1471,7 +1471,7 @@ connect and stream from you? Path to scan for music files: - + ماسار لتفحص ملفات الموسيقى: @@ -1516,27 +1516,27 @@ connect and stream from you? Use UPnP to establish port forward (recommended) - + استخدم عمل UPnP لإنشاء بوابة إعادة التوجيه (موصى به) Use static external IP address/host name and port - + استخدم عنوان/مضيف ايب (IP) و بوابة ثابتين Set this to your external IP address or host name. Make sure to forward the port to this host! - + عين هذا إلى عنوان الايب الخارجي (External IP) الخاص بك أو اسم المضيف. تأكد من إحالة البوابة إلى هذا المضيف! SOCKS Proxy - + سوكس الوكيل Use SOCKS Proxy - + استخدم سوكس الوكيل @@ -1551,7 +1551,7 @@ connect and stream from you? Filter by capability: - تصفية حسب القدرة: + ترشيح حسب القدرة: @@ -1737,7 +1737,7 @@ connect and stream from you? Sync with Spotify - + مزامنة مع سبوتيفي (Spotify) @@ -1781,7 +1781,7 @@ connect and stream from you? Connect to your Twitter followers. - تواصل مع أصدقائك على تويتر. + تواصل مع أصدقائك على تويتر (Twitter). @@ -1804,7 +1804,7 @@ connect and stream from you? Authenticate - وثق + صادق @@ -1827,7 +1827,7 @@ connect and stream from you? Tweetin' Error - + خطأ توتينغ ('Tweetin) @@ -1895,12 +1895,12 @@ You may wish to try re-authenticating. Tweeted! - + ثبت التويت (!Tweeted) Your tweet has been posted! - + رسالتك على تويتر قد نشرت! @@ -1910,7 +1910,7 @@ You may wish to try re-authenticating. Your message has been posted! - + رسالتك قد نشرت! @@ -1947,7 +1947,7 @@ You may wish to try re-authenticating. &Love - + &أحب @@ -1957,7 +1957,7 @@ You may wish to try re-authenticating. Un-&Love - + لا &أحب @@ -2120,7 +2120,7 @@ Try tweaking the filters for a new set of songs to play. is - + هو @@ -2163,32 +2163,32 @@ Try tweaking the filters for a new set of songs to play. 0 BPM - + ٠ نبضة في الدقيقة 500 BPM - + ٥٠٠ نبضة في الدقيقة 0 secs - + ٠ ثانية 3600 secs - + ٣٦٠٠ ثانية -100 dB - + -١٠٠ د.ب. 100 dB - + ١٠٠ د.ب. @@ -2203,62 +2203,62 @@ Try tweaking the filters for a new set of songs to play. C - + C C Sharp - + C Sharp D - + D E Flat - + E Flat E - + E F - + F F Sharp - + F Sharp G - + G A Flat - + A Flat A - + A B Flat - + B Flat B - + B @@ -2364,37 +2364,37 @@ Try tweaking the filters for a new set of songs to play. with %1 %2 - + مع %1 %2 about %1 BPM - + حوالي %1 نبضة في الدقيقة about %n minute(s) long - + بطول حوالي %n دقائقبطول حوالي دقيقة %nبطول حوالي دقيقتين %nبطول حوالي %n دقائقبطول حوالي %n دقائقبطول حوالي %n دقائق about %1 dB - + حوالي %1 د.ب. at around %1%2 %3 - + في حوالي %1%2 %3 in %1 - + في %1 in a %1 key - + في المفتاح %1 @@ -2404,12 +2404,12 @@ Try tweaking the filters for a new set of songs to play. with a %1 mood - + في مزاج %1 in a %1 style - + في أسلوب %1 @@ -2417,7 +2417,7 @@ Try tweaking the filters for a new set of songs to play. Steer this station: - + قد هذه الإذاعة: @@ -2427,7 +2427,7 @@ Try tweaking the filters for a new set of songs to play. Less - + أقل @@ -2502,12 +2502,12 @@ Try tweaking the filters for a new set of songs to play. Apply steering command - + طبق أوامر القيادة Reset all steering commands - + إعادة ضبط جميع أوامر القيادة @@ -2546,12 +2546,12 @@ Try tweaking the filters for a new set of songs to play. Tomahawk is playing "%1" by %2%3. - + توماهوك يلعب "%1" من قبل %2%3 on "%1" - + على "%1" @@ -2595,7 +2595,7 @@ Try tweaking the filters for a new set of songs to play. Listening to "%1" by %2 and loving it! %3 - + يتم الاستماع إلى "%1" من قبل %2 وقد أحبها! %3 @@ -2639,7 +2639,7 @@ Try tweaking the filters for a new set of songs to play. &Catch Up - + &إلحق @@ -2653,32 +2653,32 @@ Try tweaking the filters for a new set of songs to play. and - + و You - + أنت you - + أنت and - + و %n other(s) - + %n أخرين%n أخر%n أخرين%n أخرين%n أخرين%n أخرين %1 people - + %1 أشخاص @@ -2699,7 +2699,7 @@ Try tweaking the filters for a new set of songs to play. Network error parsing shortened link! - + خطأ شبكة في تحليل تقصير الرابط! @@ -2755,7 +2755,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection مجموعتي الخاصة @@ -2765,13 +2765,13 @@ Try tweaking the filters for a new set of songs to play. Twitter PIN - + رقم البن لتويتر (Twitter Pin) After authenticating on Twitter's web site, enter the displayed PIN number here: - بعد المصادقة على موقع تويتر (twitter)، + بعد المصادقة على موقع تويتر (Twitter)، أدخل رقم البين (PIN) الموجود أمامك على الشاشة هنا: @@ -2806,7 +2806,7 @@ enter the displayed PIN number here: Pause - + تعليق @@ -2854,7 +2854,7 @@ enter the displayed PIN number here: Ctrl+Q - + Ctrl+Q @@ -2884,7 +2884,7 @@ enter the displayed PIN number here: Load &XSPF... - + تحميل XSPF&... @@ -2934,7 +2934,7 @@ enter the displayed PIN number here: Meta+Ctrl+Z - + Meta+Ctrl+Z @@ -3013,22 +3013,22 @@ enter the displayed PIN number here: Enter peer address: - أدخل عنوان الصديق: + أدخل عنوان الند: Enter peer port: - أدخل بوابة الصديق: + أدخل بوابة الند: Enter peer key: - + أدخل مفتاح الند: XSPF Error - + خطأ XSPF @@ -3078,7 +3078,7 @@ enter the displayed PIN number here: Pause - + تعليق @@ -3104,13 +3104,13 @@ enter the displayed PIN number here: %1 by %2 track, artist name - + %1 من قبل %2 %1 - %2 current track, some window title - + %1 - %2 @@ -3125,7 +3125,7 @@ enter the displayed PIN number here: Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ <br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>شكر لكل من: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson @@ -3143,7 +3143,7 @@ enter the displayed PIN number here: 0 Sources - + ٠ مصادر @@ -3173,7 +3173,7 @@ enter the displayed PIN number here: Filter - + مرشح @@ -3183,7 +3183,7 @@ enter the displayed PIN number here: Flat View - + نظرة مسطحة @@ -3214,7 +3214,7 @@ enter the displayed PIN number here: Cover - + غلاف @@ -3224,7 +3224,7 @@ enter the displayed PIN number here: by - + من قبل @@ -3234,7 +3234,7 @@ enter the displayed PIN number here: from - + من @@ -3274,12 +3274,12 @@ enter the displayed PIN number here: You've listened to %1 %n time(s). - + لقد استمعت إلى %1 %n مرةلقد استمعت إلى %1 مرة %nلقد استمعت إلى %1 مرتين %nلقد استمعت إلى %1 %n مراتلقد استمعت إلى %1 %n مراتلقد استمعت إلى %1 %n مرات You've never listened to %1 before. - + لم تستمع إلى %1 من قبل. @@ -3381,17 +3381,17 @@ enter the displayed PIN number here: The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - مساعد تويتر يسمح لك بإكتشاف والإستماع إلى الموسيقى من أصدقائك على تويتر المستخدمين لتوماهوك بالإضافة إلى نشر الرسائل إلى حسابك. + مساعد تويتر (Twitter) يسمح لك بإكتشاف والإستماع إلى الموسيقى من أصدقائك على تويتر المستخدمين لتوماهوك بالإضافة إلى نشر الرسائل إلى حسابك. Status: No saved credentials - + الحالة: بيانات غير محفوظة Authenticate with Twitter - + صادق مع تويتر (Twitter) @@ -3406,12 +3406,17 @@ If you only want to post tweets, you're done. If you want to connect Tomahawk to your friends using Twitter, select the type of tweet and press the button below to send a sync message. You must both be following each other as Direct Messages are used. Then be (very) patient -- it can take several minutes! You can re-send a sync message at any time simply by sending another tweet using the button. - + +إن كنت تريد نشر التويت (Tweet) فقط، لقد انتهيت! + +إن كنت تريد لتوماهوك الاتصال بأصدقائك من خلال تويتر (Twitter)، حدد نوع التويت (Tweet) و إضغط على الزر أدناه لإرسال رسالة مزامنة. يجب أن تكونا تابعين لبعضكما البعض على حد سواء لأن الرسائل المباشرة تستخدم. ثم يجب الإنتظار بصبر (كبير) - يمكن أن تستغرق العملية عدة دقائق! + +يمكنك إعادة إرسال رسالة المزامنة في أي وقت عن طريق إرسال تويت (Tweet) آخر بضغط هذا الزر من جديد. Select the kind of tweet you would like, then press the button to post it: - + حدد نوع التويت (Tweet) اللذي ترغب به، ثم إضغط على الزر لنشره: @@ -3421,12 +3426,12 @@ You can re-send a sync message at any time simply by sending another tweet using @Mention - + @ذكر Direct Message - + رسالة مباشرة @@ -3436,7 +3441,7 @@ You can re-send a sync message at any time simply by sending another tweet using Send Message - + إرسل رسالة @@ -3500,7 +3505,7 @@ You can re-send a sync message at any time simply by sending another tweet using Charts - + الرسوم البيانية @@ -3508,7 +3513,7 @@ You can re-send a sync message at any time simply by sending another tweet using Wikipedia - + ويكيبيديا @@ -3518,26 +3523,30 @@ You can re-send a sync message at any time simply by sending another tweet using Terms for %1: - + شروط %1: No terms found, sorry. - + لا شروط موجودة، نتأسف Hotttness for %1: %2 - + +شعبية %1:%2 + Familiarity for %1: %2 - + +ألفت %1:%2 + @@ -3546,7 +3555,11 @@ Lyrics for "%1" by %2: %3 - + +كلمات أغاني "%1" من قبل %2" + +%3 + @@ -3577,13 +3590,13 @@ Lyrics for "%1" by %2: Xml stream console - + Xml stream console Filter - + مرشح @@ -3598,22 +3611,22 @@ Lyrics for "%1" by %2: By JID - + By JID By namespace uri - + By namespace uri By all attributes - + By all attributes Visible stanzas - + Visible stanzas @@ -3623,12 +3636,12 @@ Lyrics for "%1" by %2: Message - + رسالة Presence - + Presence @@ -3643,7 +3656,7 @@ Lyrics for "%1" by %2: Save XMPP log to file - + Save XMPP log to file @@ -3656,7 +3669,7 @@ Lyrics for "%1" by %2: Xmpp Configuration - + تكوينات أكسمبب (XMPP) @@ -3676,7 +3689,7 @@ Lyrics for "%1" by %2: Xmpp ID: - + تعريف أكسمبب (XMPP ID): @@ -3696,7 +3709,7 @@ Lyrics for "%1" by %2: Advanced Xmpp Settings - + إعدادات أكسمبب (XMPP) المتقدمة @@ -3706,7 +3719,7 @@ Lyrics for "%1" by %2: Port: - + بوابة: @@ -3749,7 +3762,7 @@ Lyrics for "%1" by %2: Remote Stream Error - + خطأ في التحميل (المجرى) البعيد @@ -3764,7 +3777,7 @@ Lyrics for "%1" by %2: System shutdown - + إغلاق النظام @@ -3774,7 +3787,7 @@ Lyrics for "%1" by %2: Unknown - + مجهول @@ -3804,7 +3817,7 @@ Lyrics for "%1" by %2: Enter Xmpp ID: - + أدخل تعريف أكسمبب (XMPP ID): @@ -3814,7 +3827,7 @@ Lyrics for "%1" by %2: XML Console... - + وحدة التحكم XML... diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 8497710f6..07f5e535c 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -2760,7 +2760,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index bd305113d..3dcd039eb 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -2754,7 +2754,7 @@ Intenteu ajustar els filtres per reproduir noves cançons.
    TomahawkApp - + My Collection La meva Col·lecció diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 534ce3f2e..f30d64a57 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -2749,7 +2749,7 @@ Versuch die Filter anzupassen für neue Lieder.
    TomahawkApp - + My Collection Meine Sammlung diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 9228c9c7c..ae6834e95 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -2755,7 +2755,7 @@ Try tweaking the filters for a new set of songs to play.
    TomahawkApp - + My Collection My Collection diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index b369935ef..1d9f76567 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -2753,7 +2753,7 @@ Intente ajustar los filtros para reproducir nuevas canciones.
    TomahawkApp - + My Collection Mi colección diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index adb30ef95..fb64e581e 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -2755,7 +2755,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. TomahawkApp - + My Collection Ma Collection diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index ca558174e..0af066503 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -2745,7 +2745,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 1e2c68330..3f5fdeb4d 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -2749,7 +2749,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 8ccb5af8c..878548c70 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -2748,7 +2748,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 17b8b0d15..75c925bd9 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -2750,7 +2750,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index bc7e74b33..01f8c5dfa 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -2744,7 +2744,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 6772683eb..0345e80ea 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -2743,7 +2743,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index c456c80c0..c04d5bd1f 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -2743,7 +2743,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 555b1bdf0..38331b37f 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -2743,7 +2743,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection 我的收藏 From 1c55f56777d6fa1873fe721058e5f15af09a674f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 25 May 2012 07:49:28 +0200 Subject: [PATCH 075/433] * A little dependency tracking. --- src/AudioControls.cpp | 2 +- src/TomahawkWindow.cpp | 21 +++++----- src/libtomahawk/ViewManager.cpp | 42 +++++++++++++++++++ src/libtomahawk/ViewManager.h | 16 ++++--- src/libtomahawk/infobar/InfoBar.cpp | 10 ++--- .../playlist/AlbumItemDelegate.cpp | 2 +- src/libtomahawk/playlist/AlbumView.cpp | 2 + src/libtomahawk/playlist/ArtistView.cpp | 2 + src/libtomahawk/playlist/TrackView.cpp | 2 +- src/libtomahawk/widgets/NewReleasesWidget.cpp | 2 +- src/libtomahawk/widgets/NewReleasesWidget.h | 2 - src/libtomahawk/widgets/SearchWidget.cpp | 2 +- src/libtomahawk/widgets/WhatsHotWidget.cpp | 2 +- src/libtomahawk/widgets/WhatsHotWidget.h | 2 - .../widgets/infowidgets/AlbumInfoWidget.cpp | 2 +- .../widgets/infowidgets/SourceInfoWidget.cpp | 2 +- .../widgets/infowidgets/TrackInfoWidget.cpp | 2 +- src/sourcetree/SourceTreeView.cpp | 3 +- 18 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 9080753f8..6a1e639c3 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -28,7 +28,7 @@ #include "playlist/PlaylistView.h" #include "database/Database.h" #include "widgets/ImageButton.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Album.h" #include "DropJob.h" diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 3a95b1bcb..bb325da05 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -35,13 +35,10 @@ #include #include -#include "Playlist.h" -#include "Query.h" -#include "Artist.h" -#include "ViewManager.h" #include "accounts/AccountManager.h" #include "sourcetree/SourceTreeView.h" #include "network/Servent.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/ProxyStyle.h" #include "widgets/AnimatedSplitter.h" #include "widgets/NewPlaylistWidget.h" @@ -52,27 +49,31 @@ #include "playlist/PlaylistModel.h" #include "playlist/PlaylistView.h" #include "playlist/QueueView.h" +#include "jobview/JobStatusView.h" +#include "jobview/JobStatusModel.h" +#include "jobview/ErrorStatusMessage.h" +#include "jobview/JobStatusModel.h" +#include "Playlist.h" +#include "Query.h" +#include "Artist.h" +#include "ViewManager.h" +#include "ActionCollection.h" #include "AudioControls.h" #include "SettingsDialog.h" #include "DiagnosticsDialog.h" #include "TomahawkSettings.h" #include "SourceList.h" -#include "jobview/JobStatusView.h" -#include "jobview/JobStatusModel.h" -#include "jobview/ErrorStatusMessage.h" #include "TomahawkTrayIcon.h" #include "ScanManager.h" #include "TomahawkApp.h" +#include "LoadXSPFDialog.h" #ifdef Q_WS_WIN #include #endif #include "utils/Logger.h" -#include "jobview/JobStatusModel.h" -#include "LoadXSPFDialog.h" -#include using namespace Tomahawk; using namespace Accounts; diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 07b9ba533..8afa38db3 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -46,6 +46,7 @@ #include "RecentlyPlayedModel.h" #include "dynamic/widgets/DynamicWidget.h" +#include "widgets/NewReleasesWidget.h" #include "widgets/WelcomeWidget.h" #include "widgets/WhatsHotWidget.h" #include "widgets/infowidgets/SourceInfoWidget.h" @@ -1025,3 +1026,44 @@ ViewManager::showCurrentTrack() } } + +Tomahawk::ViewPage* +ViewManager::welcomeWidget() const +{ + return m_welcomeWidget; +} + + +Tomahawk::ViewPage* +ViewManager::whatsHotWidget() const +{ + return m_whatsHotWidget; +} + + +Tomahawk::ViewPage* +ViewManager::newReleasesWidget() const +{ + return m_newReleasesWidget; +} + + +Tomahawk::ViewPage* +ViewManager::topLovedWidget() const +{ + return m_topLovedWidget; +} + + +Tomahawk::ViewPage* +ViewManager::recentPlaysWidget() const +{ + return m_recentPlaysWidget; +} + + +ArtistView* +ViewManager::superCollectionView() const +{ + return m_superCollectionView; +} diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index 2ac07447f..85702642b 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -29,9 +29,6 @@ #include "PlaylistInterface.h" #include "playlist/QueueView.h" #include "ViewPage.h" -#include "widgets/WelcomeWidget.h" -#include "widgets/WhatsHotWidget.h" -#include "widgets/NewReleasesWidget.h" #include "DllMacro.h" @@ -56,6 +53,7 @@ class SourceInfoWidget; class InfoBar; class TopBar; class TrackInfoWidget; +class NewReleasesWidget; class WelcomeWidget; class WhatsHotWidget; class QPushButton; @@ -91,12 +89,12 @@ public: Tomahawk::ViewPage* show( Tomahawk::ViewPage* page ); - Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; } - Tomahawk::ViewPage* whatsHotWidget() const { return m_whatsHotWidget; } - Tomahawk::ViewPage* newReleasesWidget() const { return m_newReleasesWidget; } - Tomahawk::ViewPage* topLovedWidget() const { return m_topLovedWidget; } - Tomahawk::ViewPage* recentPlaysWidget() const { return m_recentPlaysWidget; } - ArtistView* superCollectionView() const { return m_superCollectionView; } + Tomahawk::ViewPage* welcomeWidget() const; + Tomahawk::ViewPage* whatsHotWidget() const; + Tomahawk::ViewPage* newReleasesWidget() const; + Tomahawk::ViewPage* topLovedWidget() const; + Tomahawk::ViewPage* recentPlaysWidget() const; + ArtistView* superCollectionView() const; /// Get the view page for the given item. Not pretty... Tomahawk::ViewPage* pageForPlaylist( const Tomahawk::playlist_ptr& pl ) const; diff --git a/src/libtomahawk/infobar/InfoBar.cpp b/src/libtomahawk/infobar/InfoBar.cpp index 0aaca0c59..ae786f64d 100644 --- a/src/libtomahawk/infobar/InfoBar.cpp +++ b/src/libtomahawk/infobar/InfoBar.cpp @@ -22,14 +22,14 @@ #include #include - -#include "ViewManager.h" -#include "thirdparty/Qocoa/qsearchfield.h" -#include "utils/TomahawkUtils.h" -#include "utils/Logger.h" #include #include #include + +#include "ViewManager.h" +#include "thirdparty/Qocoa/qsearchfield.h" +#include "utils/TomahawkUtilsGui.h" +#include "utils/Logger.h" #include #define ANIMATION_TIME 400 diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index c05ee89a4..0f262f44e 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -31,7 +31,7 @@ #include "Source.h" #include "audio/AudioEngine.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/PixmapDelegateFader.h" #include diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 03c5eaa8b..1bcd30565 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -29,6 +29,7 @@ #include "context/ContextWidget.h" #include "TomahawkSettings.h" #include "Artist.h" +#include "Source.h" #include "PlayableItem.h" #include "AlbumItemDelegate.h" #include "AlbumModel.h" @@ -36,6 +37,7 @@ #include "ViewManager.h" #include "utils/Logger.h" #include "utils/AnimatedSpinner.h" +#include "utils/TomahawkUtilsGui.h" #define SCROLL_TIMEOUT 280 diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/ArtistView.cpp index 993a875b6..e080847f0 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/ArtistView.cpp @@ -35,7 +35,9 @@ #include "TreeItemDelegate.h" #include "TreeModel.h" #include "PlayableItem.h" +#include "Source.h" #include "ViewManager.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #define SCROLL_TIMEOUT 280 diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index af3cb230e..f1d00f2b5 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -31,7 +31,7 @@ #include "audio/AudioEngine.h" #include "context/ContextWidget.h" #include "widgets/OverlayWidget.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "utils/Closure.h" #include "DropJob.h" diff --git a/src/libtomahawk/widgets/NewReleasesWidget.cpp b/src/libtomahawk/widgets/NewReleasesWidget.cpp index e57820603..68636a8f1 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.cpp +++ b/src/libtomahawk/widgets/NewReleasesWidget.cpp @@ -39,7 +39,7 @@ #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" #include "widgets/OverlayWidget.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Pipeline.h" diff --git a/src/libtomahawk/widgets/NewReleasesWidget.h b/src/libtomahawk/widgets/NewReleasesWidget.h index f61afb398..c26e4eefc 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.h +++ b/src/libtomahawk/widgets/NewReleasesWidget.h @@ -30,8 +30,6 @@ #include "infosystem/InfoSystem.h" #include "ViewPage.h" -#include "utils/TomahawkUtils.h" - #include "DllMacro.h" class QSortFilterProxyModel; diff --git a/src/libtomahawk/widgets/SearchWidget.cpp b/src/libtomahawk/widgets/SearchWidget.cpp index b99d462b5..1ad389472 100644 --- a/src/libtomahawk/widgets/SearchWidget.cpp +++ b/src/libtomahawk/widgets/SearchWidget.cpp @@ -30,7 +30,7 @@ #include "widgets/OverlayWidget.h" #include "utils/AnimatedSpinner.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index 4cc7b7ca7..5fadd8bc1 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -38,7 +38,7 @@ #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" #include "widgets/OverlayWidget.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Pipeline.h" diff --git a/src/libtomahawk/widgets/WhatsHotWidget.h b/src/libtomahawk/widgets/WhatsHotWidget.h index cb8a8f635..d192fad92 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.h +++ b/src/libtomahawk/widgets/WhatsHotWidget.h @@ -29,8 +29,6 @@ #include "infosystem/InfoSystem.h" #include "ViewPage.h" -#include "utils/TomahawkUtils.h" - #include "DllMacro.h" class QSortFilterProxyModel; diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 4f84b29f5..4fc2a5d6a 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -30,7 +30,7 @@ #include "database/DatabaseCommand_AllTracks.h" #include "database/DatabaseCommand_AllAlbums.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "widgets/OverlayButton.h" diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp index e6f51088a..ebc46a80a 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp @@ -30,7 +30,7 @@ #include "database/Database.h" #include "database/DatabaseCommand_AllAlbums.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "widgets/OverlayWidget.h" diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 29e4bc68e..eaedf96fa 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -26,7 +26,7 @@ #include "playlist/AlbumModel.h" #include "audio/AudioEngine.h" -#include "utils/TomahawkUtils.h" +#include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" using namespace Tomahawk; diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index c47ce9617..c73853c92 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -42,12 +42,13 @@ #include "TomahawkSettings.h" #include "GlobalActionManager.h" #include "DropJob.h" -#include "utils/Logger.h" #include "items/GenericPageItems.h" #include "items/TemporaryPageItem.h" #include "database/DatabaseCommand_SocialAction.h" #include "database/Database.h" #include "LatchManager.h" +#include "utils/TomahawkUtilsGui.h" +#include "utils/Logger.h" using namespace Tomahawk; From da3bf8d43ffb5ba770db12efd58014dd8e377f57 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 08:52:10 -0400 Subject: [PATCH 076/433] Fix warning --- src/libtomahawk/PlaylistInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/PlaylistInterface.cpp b/src/libtomahawk/PlaylistInterface.cpp index 4cfefcab9..a8b24ebb8 100644 --- a/src/libtomahawk/PlaylistInterface.cpp +++ b/src/libtomahawk/PlaylistInterface.cpp @@ -21,6 +21,7 @@ #include "utils/Logger.h" #include "Result.h" #include "Pipeline.h" +#include "Source.h" using namespace Tomahawk; @@ -68,7 +69,7 @@ PlaylistInterface::filterTracks( const QList& queries ) break; const query_ptr& q2 = result.at( j ); - + if ( q1->track() == q2->track() ) { picked = false; From 9521ed3fde9995d169847cfc2d86e1b2f2dfad9e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 09:02:34 -0400 Subject: [PATCH 077/433] More warning fixes --- src/AudioControls.cpp | 1 + src/libtomahawk/infobar/InfoBar.cpp | 3 ++- src/libtomahawk/playlist/PlaylistView.cpp | 1 + src/libtomahawk/playlist/TrackView.cpp | 1 + src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 6a1e639c3..58e6fba06 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -35,6 +35,7 @@ #include "SocialWidget.h" #include "GlobalActionManager.h" #include "ViewManager.h" +#include "Source.h" using namespace Tomahawk; diff --git a/src/libtomahawk/infobar/InfoBar.cpp b/src/libtomahawk/infobar/InfoBar.cpp index ae786f64d..84f334658 100644 --- a/src/libtomahawk/infobar/InfoBar.cpp +++ b/src/libtomahawk/infobar/InfoBar.cpp @@ -30,7 +30,8 @@ #include "thirdparty/Qocoa/qsearchfield.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include +#include "widgets/QueryLabel.h" +#include "Source.h" #define ANIMATION_TIME 400 #define IMAGE_HEIGHT 64 diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index 3fb6f7426..fc748fd19 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -27,6 +27,7 @@ #include "ViewManager.h" #include "utils/Logger.h" #include "PlaylistUpdaterInterface.h" +#include "Source.h" using namespace Tomahawk; diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index f1d00f2b5..5049758b9 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -37,6 +37,7 @@ #include "DropJob.h" #include "Artist.h" #include "Album.h" +#include "Source.h" #include "utils/AnimatedSpinner.h" #define SCROLL_TIMEOUT 280 diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 4fc2a5d6a..4131f3a6d 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -26,6 +26,7 @@ #include "database/Database.h" #include "playlist/TreeModel.h" #include "playlist/AlbumModel.h" +#include "Source.h" #include "database/DatabaseCommand_AllTracks.h" #include "database/DatabaseCommand_AllAlbums.h" From 26036a202190291a460d44d44e8fe67004248727 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 12:12:15 -0400 Subject: [PATCH 078/433] Only turn on enable account when going back online --- src/libtomahawk/accounts/AccountManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 22ab46d78..75db452ee 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -234,8 +234,11 @@ AccountManager::connectAll() tDebug( LOGVERBOSE ) << Q_FUNC_INFO; foreach( Account* acc, m_accounts ) { - acc->authenticate(); - m_enabledAccounts << acc; + if ( acc->enabled() ) + { + acc->authenticate(); + m_enabledAccounts << acc; + } } m_connected = true; From fb5d21e4018bd178e4c35597ab191b883b9cefd2 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 12:35:28 -0400 Subject: [PATCH 079/433] Add a cmake flag to disable binary attica resolvers for distros --- CMakeLists.txt | 1 + src/Config.h.in | 2 ++ src/libtomahawk/AtticaManager.cpp | 8 +++++++- src/libtomahawk/accounts/AccountModel.cpp | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index edfd21fcc..e8f136639 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(BUILD_GUI "Build Tomahawk with GUI" ON) option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF) option(WITH_BREAKPAD "Build with breakpad integration" ON) option(WITH_CRASHREPORTER "Build with CrashReporter" ON) +option(WITH_BINARY_ATTICA "Enable support for downloading binary resolvers automatically" ON) option(LEGACY_KDE_INTEGRATION "Install tomahawk.protocol file, deprecated since 4.6.0" OFF) IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" ) diff --git a/src/Config.h.in b/src/Config.h.in index c6172e0d9..1aa764c96 100644 --- a/src/Config.h.in +++ b/src/Config.h.in @@ -19,6 +19,8 @@ #cmakedefine WITH_BREAKPAD #cmakedefine WITH_CRASHREPORTER +#cmakedefine WITH_BINARY_ATTICA + #cmakedefine LIBLASTFM_FOUND #cmakedefine QCA2_FOUND diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index 450676e27..f98af7161 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -22,6 +22,7 @@ #include "TomahawkSettingsGui.h" #include "Pipeline.h" #include "Source.h" +#include "config.h" #include @@ -373,7 +374,12 @@ AtticaManager::binaryResolversList( BaseJob* j ) platform = "linux-x64"; #elif defined(Q_OS_LINUX) // Horrible assumption here... platform = "linux-x86"; - #endif +#endif + + // Override if no binary resolvers were requested +#ifndef WITH_BINARY_ATTICA + platform = QString(); +#endif foreach ( const Content& c, binaryResolvers ) { diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index c5b341289..61ae6e71e 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -522,7 +522,7 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role box.setWindowTitle( tr( "Manual Install Required" ) ); box.setTextFormat( Qt::RichText ); box.setIcon( QMessageBox::Information ); - box.setText( tr( "Unfortunately, automatic installation of this resolver is not yet available on Linux.

    " + box.setText( tr( "Unfortunately, automatic installation of this resolver is not available or disabled for your platform.

    " "Please use \"Install from file\" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:

    http://www.tomahawk-player.org/resolvers/%1" ).arg( acct->accountServiceName() ) ); box.setStandardButtons( QMessageBox::Ok ); box.exec(); From 098183ddca3f0131efaea78107aa911a47746c10 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 14:14:06 -0400 Subject: [PATCH 080/433] Keep Remove button size in accounts delegate same as Add --- src/AccountDelegate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/AccountDelegate.cpp b/src/AccountDelegate.cpp index 1d7a23c01..77eb60bfe 100644 --- a/src/AccountDelegate.cpp +++ b/src/AccountDelegate.cpp @@ -281,7 +281,10 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, btnRect = QRect( opt.rect.right() - PADDING - btnWidth, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 2*PADDING ); #ifdef Q_WS_MAC - btnRect.adjust( -4, 2, 4, -2 ); + btnRect.adjust( -4, 0, 4, 0 ); + + if ( hasConfigWrench ) + btnRect.moveTop( btnRect.top() + 2 ); #endif leftEdge = btnRect.left(); m_cachedButtonRects[ index ] = btnRect; From 37b59126f6c7f211b4582a4dd8971cb139518a2e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 15:13:40 -0400 Subject: [PATCH 081/433] Sort binary resolvers, then script resolvers by download count --- src/libtomahawk/AtticaManager.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index f98af7161..b3de882e6 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -42,6 +42,15 @@ using namespace Attica; AtticaManager* AtticaManager::s_instance = 0; +// Sort binary resolvers above script resolvers, and script resolvers by download count +bool +resolverSort( const Attica::Content& first, const Attica::Content& second ) +{ + if ( !first.attribute( "typeid" ).isEmpty() && second.attribute( "typeid" ).isEmpty() ) + return true; + + return first.downloads() > second.downloads(); +} AtticaManager::AtticaManager( QObject* parent ) : QObject( parent ) @@ -353,7 +362,10 @@ AtticaManager::resolversList( BaseJob* j ) syncServerData(); if ( ++m_resolverJobsLoaded == 2 ) + { + qSort( m_resolvers.begin(), m_resolvers.end(), resolverSort ); emit resolversLoaded( m_resolvers ); + } } @@ -404,7 +416,10 @@ AtticaManager::binaryResolversList( BaseJob* j ) } if ( ++m_resolverJobsLoaded == 2 ) + { + qSort( m_resolvers.begin(), m_resolvers.end(), resolverSort ); emit resolversLoaded( m_resolvers ); + } } From 873b8dab91a5b76571fe7d59a15db4797ffa2571 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 15:13:53 -0400 Subject: [PATCH 082/433] Assert if we forcibly kill external resolvers, to get some user feedback --- src/libtomahawk/resolvers/ScriptResolver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 6e66fb6d6..009dc401e 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -76,6 +76,7 @@ ScriptResolver::~ScriptResolver() if ( !finished || m_proc.state() == QProcess::Running ) { qDebug() << "External resolver didn't exit after waiting 2s for it to die, killing forcefully"; + Q_ASSERT(false); #ifdef Q_OS_WIN m_proc.kill(); #else From 3cac23523245d97f4c81263922282ad37c4a533c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 15:38:48 -0400 Subject: [PATCH 083/433] TWK-888: Steer text color should be highlighted text color --- .../playlist/dynamic/echonest/EchonestSteerer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp index f9c983b9e..28b496649 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp @@ -66,6 +66,11 @@ EchonestSteerer::EchonestSteerer( QWidget* parent ) // m_steerBottom->setFont( f ); // m_textL->addWidget( m_steerBottom ); + + QPalette p = m_steerTop->palette(); + p.setBrush( QPalette::WindowText, palette().highlightedText() ); + m_steerTop->setPalette( p ); + m_layout->addLayout( m_textL, 1 ); m_amplifier = new QComboBox( this ); From 075d5e74f8e9b7a8df735e264e41ef64832379cd Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 16:20:48 -0400 Subject: [PATCH 084/433] TWK-903: Resize last.fm dialog when beginning to import --- src/DelegateConfigWrapper.cpp | 3 --- src/accounts/lastfm/LastFmConfig.cpp | 2 ++ src/accounts/lastfm/LastFmConfig.h | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/DelegateConfigWrapper.cpp b/src/DelegateConfigWrapper.cpp index abd1de5ad..fccd60606 100644 --- a/src/DelegateConfigWrapper.cpp +++ b/src/DelegateConfigWrapper.cpp @@ -124,12 +124,9 @@ DelegateConfigWrapper::rejected() void DelegateConfigWrapper::updateSizeHint() { - hide(); setSizeGripEnabled( false ); setMinimumSize( sizeHint() ); setMaximumSize( sizeHint() ); - - show(); } diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index 9fd240abe..c9fdcf357 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -119,6 +119,8 @@ LastFmConfig::loadHistory() m_ui->importHistory->setEnabled( false ); m_ui->progressBar->show(); + emit sizeHintChanged(); + QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, m_page ); connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) ); } diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/accounts/lastfm/LastFmConfig.h index cc6bfc8fb..c7c53f2b9 100644 --- a/src/accounts/lastfm/LastFmConfig.h +++ b/src/accounts/lastfm/LastFmConfig.h @@ -49,6 +49,9 @@ private slots: void loadHistory(); void onHistoryLoaded(); +signals: + void sizeHintChanged(); + private: LastFmAccount* m_account; Ui_LastFmConfig* m_ui; From 9bdeed232e8f0bf1a87cc548eb04befb4b050af7 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 17:01:03 -0400 Subject: [PATCH 085/433] Fix typo --- src/breakpad/CrashReporter/CrashReporter.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/breakpad/CrashReporter/CrashReporter.ui b/src/breakpad/CrashReporter/CrashReporter.ui index 10d1d406f..8cfe575fb 100644 --- a/src/breakpad/CrashReporter/CrashReporter.ui +++ b/src/breakpad/CrashReporter/CrashReporter.ui @@ -77,7 +77,7 @@ - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> Qt::RichText From 3710d617a1bd15637c56fa56185102b073791a36 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 16:49:55 -0400 Subject: [PATCH 086/433] Load 22x22 track-info icon --- src/sourcetree/items/TemporaryPageItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcetree/items/TemporaryPageItem.cpp b/src/sourcetree/items/TemporaryPageItem.cpp index 669948e33..765e39509 100644 --- a/src/sourcetree/items/TemporaryPageItem.cpp +++ b/src/sourcetree/items/TemporaryPageItem.cpp @@ -36,7 +36,7 @@ TemporaryPageItem::TemporaryPageItem ( SourcesModel* mdl, SourceTreeItem* parent else if ( dynamic_cast< AlbumInfoWidget* >( page ) ) m_icon = QIcon( RESPATH "images/album-icon.png" ); else if ( dynamic_cast< TrackInfoWidget* >( page ) ) - m_icon = QIcon( RESPATH "images/track-icon.png" ); + m_icon = QIcon( RESPATH "images/track-icon-22x22.png" ); else if ( dynamic_cast< SearchWidget* >( page ) ) m_icon = QIcon( RESPATH "images/search-icon.png" ); From ac46b080fe4c8ef15f5f932cd36dbe08ce54ee7c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 17:12:33 -0400 Subject: [PATCH 087/433] Only show updater icon if updater is actively syncing --- src/accounts/spotify/SpotifyAccount.cpp | 11 +++++++++-- src/libtomahawk/playlist/PlaylistUpdaterInterface.h | 2 ++ src/sourcetree/items/PlaylistItems.cpp | 9 +-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index a05dc6e5c..16b9e22a0 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -342,13 +342,16 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) // If it's not being synced, allow the option to sync bool found = false; + bool manuallyDisabled = false; QList updaters = playlist->updaters(); foreach ( PlaylistUpdaterInterface* updater, updaters ) { if ( SpotifyPlaylistUpdater* spotifyUpdater = qobject_cast< SpotifyPlaylistUpdater* >( updater ) ) { - if ( spotifyUpdater->sync() ) - found = true; + found = true; + if ( !spotifyUpdater->sync() ) + manuallyDisabled = true; + } } @@ -356,6 +359,10 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) { action->setText( tr( "Sync with Spotify" ) ); } + else if ( manuallyDisabled ) + { + action->setText( tr( "Re-enable syncing with Spotify" ) ); + } else { action->setText( tr( "Stop syncing with Spotify" ) ); diff --git a/src/libtomahawk/playlist/PlaylistUpdaterInterface.h b/src/libtomahawk/playlist/PlaylistUpdaterInterface.h index b05621995..0776451bd 100644 --- a/src/libtomahawk/playlist/PlaylistUpdaterInterface.h +++ b/src/libtomahawk/playlist/PlaylistUpdaterInterface.h @@ -71,6 +71,8 @@ public: static void registerUpdaterFactory( PlaylistUpdaterFactory* f ); + virtual bool sync() const { return true; } + signals: void changed(); diff --git a/src/sourcetree/items/PlaylistItems.cpp b/src/sourcetree/items/PlaylistItems.cpp index f7b37ac5a..d0bebc7a4 100644 --- a/src/sourcetree/items/PlaylistItems.cpp +++ b/src/sourcetree/items/PlaylistItems.cpp @@ -251,13 +251,6 @@ PlaylistItem::parsedDroppedTracks( const QList< query_ptr >& tracks ) void PlaylistItem::onUpdated() { - // No work todo - if ( !m_overlaidIcon.isNull() && m_overlaidUpdaters.operator==( m_playlist->updaters() ) ) - { - emit updated(); - return; - } - const bool newOverlay = createOverlay(); if ( !newOverlay && !m_overlaidIcon.isNull() ) m_overlaidIcon = QIcon(); @@ -278,7 +271,7 @@ PlaylistItem::createOverlay() QList< QPixmap > icons; foreach ( PlaylistUpdaterInterface* updater, m_playlist->updaters() ) { - if ( !updater->typeIcon().isNull() ) + if ( updater->sync() && !updater->typeIcon().isNull() ) icons << updater->typeIcon(); } From f9470056664f421f3ee8070d17ad7e03bf43474f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 25 May 2012 18:08:09 -0400 Subject: [PATCH 088/433] TWK-885: Hide resize handle when in osx full-screen mode --- src/TomahawkApp.cpp | 2 +- src/TomahawkWindow.cpp | 38 ++++++++++++++++++++++++++------------ src/TomahawkWindow.h | 3 +++ src/mac/TomahawkApp_Mac.h | 5 ++++- src/mac/TomahawkApp_Mac.mm | 24 +++++++++++++++++++++++- 5 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 796b4392a..f98bce7b1 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -306,7 +306,7 @@ TomahawkApp::init() #ifdef Q_WS_MAC // Make sure to do this after main window is inited - Tomahawk::enableFullscreen(); + Tomahawk::enableFullscreen( m_mainwindow ); #endif } diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index bb325da05..10996b4a1 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -192,7 +192,7 @@ TomahawkWindow::applyPlatformTweaks() if ( !QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) ) qApp->setStyle( new ProxyStyle() ); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC setUnifiedTitleAndToolBarOnMac( true ); delete ui->hline1; delete ui->hline2; @@ -272,7 +272,7 @@ TomahawkWindow::setupSideBar() sidebarWidget->layout()->setContentsMargins( 0, 0, 0, 0 ); sidebarWidget->layout()->setMargin( 0 ); -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC sidebarWidget->layout()->setSpacing( 0 ); #endif @@ -287,11 +287,11 @@ TomahawkWindow::setupSideBar() void TomahawkWindow::setupUpdateCheck() { -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC ui->menu_Help->insertSeparator( ui->actionAboutTomahawk ); #endif -#if defined( Q_WS_MAC ) && defined( HAVE_SPARKLE ) +#if defined( Q_OS_MAC ) && defined( HAVE_SPARKLE ) QAction* checkForUpdates = ui->menu_Help->addAction( tr( "Check For Updates..." ) ); checkForUpdates->setMenuRole( QAction::ApplicationSpecificRole ); connect( checkForUpdates, SIGNAL( triggered( bool ) ), SLOT( checkForUpdates() ) ); @@ -350,7 +350,7 @@ TomahawkWindow::setupSignals() connect( ui->actionNext, SIGNAL( triggered() ), AudioEngine::instance(), SLOT( next() ) ); connect( ui->actionPrevious, SIGNAL( triggered() ), AudioEngine::instance(), SLOT( previous() ) ); -#if defined( Q_WS_MAC ) +#if defined( Q_OS_MAC ) connect( ui->actionMinimize, SIGNAL( triggered() ), SLOT( minimize() ) ); connect( ui->actionZoom, SIGNAL( triggered() ), SLOT( maximize() ) ); #else @@ -399,7 +399,7 @@ TomahawkWindow::changeEvent( QEvent* e ) void TomahawkWindow::closeEvent( QCloseEvent* e ) { -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC if ( e->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable() ) { hide(); @@ -419,7 +419,7 @@ TomahawkWindow::showEvent( QShowEvent* e ) { QMainWindow::showEvent( e ); -#if defined( Q_WS_MAC ) +#if defined( Q_OS_MAC ) ui->actionMinimize->setDisabled( false ); ui->actionZoom->setDisabled( false ); #endif @@ -431,7 +431,7 @@ TomahawkWindow::hideEvent( QHideEvent* e ) { QMainWindow::hideEvent( e ); -#if defined( Q_WS_MAC ) +#if defined( Q_OS_MAC ) ui->actionMinimize->setDisabled( true ); ui->actionZoom->setDisabled( true ); #endif @@ -442,7 +442,7 @@ void TomahawkWindow::keyPressEvent( QKeyEvent* e ) { bool accept = true; -#if ! defined ( Q_WS_MAC ) +#if ! defined ( Q_OS_MAC ) #define KEY_PRESSED Q_FUNC_INFO << "Multimedia Key Pressed:" switch( e->key() ) { @@ -590,11 +590,25 @@ TomahawkWindow::showOfflineSources() } +void +TomahawkWindow::fullScreenEntered() +{ + statusBar()->setSizeGripEnabled( false ); +} + + +void +TomahawkWindow::fullScreenExited() +{ + statusBar()->setSizeGripEnabled( true ); +} + + void TomahawkWindow::loadSpiff() { LoadXSPFDialog* diag = new LoadXSPFDialog( this, Qt::Sheet ); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC connect( diag, SIGNAL( finished( int ) ), this, SLOT( loadXspfFinished( int ) ) ); diag->show(); #else @@ -719,7 +733,7 @@ void TomahawkWindow::createPlaylist() { PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet ); -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC playlistSelectorDlg->setModal( true ); #endif connect( playlistSelectorDlg, SIGNAL( finished( int ) ), this, SLOT( playlistCreateDialogFinished( int ) ) ); @@ -863,7 +877,7 @@ TomahawkWindow::showAboutTomahawk() void TomahawkWindow::checkForUpdates() { -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC Tomahawk::checkForUpdates(); #endif } diff --git a/src/TomahawkWindow.h b/src/TomahawkWindow.h index d0f0cdaa1..a0bde3cda 100644 --- a/src/TomahawkWindow.h +++ b/src/TomahawkWindow.h @@ -88,6 +88,9 @@ public slots: void pluginMenuRemoved(QMenu*); void showOfflineSources(); + void fullScreenEntered(); + void fullScreenExited(); + private slots: void onAccountAdded( Tomahawk::Accounts::Account* account ); void onAccountConnected(); diff --git a/src/mac/TomahawkApp_Mac.h b/src/mac/TomahawkApp_Mac.h index e0957177f..e258c6719 100644 --- a/src/mac/TomahawkApp_Mac.h +++ b/src/mac/TomahawkApp_Mac.h @@ -23,6 +23,7 @@ // copyright David Sansome 2010 class QString; +class QObject; namespace Tomahawk { @@ -43,7 +44,9 @@ void setShortcutHandler(Tomahawk::MacShortcutHandler* engine); // used for opening files with tomahawk void setApplicationHandler(PlatformInterface* handler); void checkForUpdates(); -void enableFullscreen(); + +// Pass in a QObject with slots "fullScreenEntered() and fullScreenExited() in order to be notified +void enableFullscreen( QObject* notifier ); }; diff --git a/src/mac/TomahawkApp_Mac.mm b/src/mac/TomahawkApp_Mac.mm index 6187fab4e..402fb4c7f 100644 --- a/src/mac/TomahawkApp_Mac.mm +++ b/src/mac/TomahawkApp_Mac.mm @@ -43,6 +43,8 @@ #include #include +#include +#include @interface MacApplication :NSApplication { AppDelegate* delegate_; @@ -255,7 +257,7 @@ void Tomahawk::checkForUpdates() { #define SET_LION_FULLSCREEN (NSUInteger)(1 << 7) // Defined as NSWindowCollectionBehaviorFullScreenPrimary in lion's NSWindow.h #endif -void Tomahawk::enableFullscreen() +void Tomahawk::enableFullscreen( QObject* receiver ) { // We don't support anything below leopard, so if it's not [snow] leopard it must be lion // Can't check for lion as Qt 4.7 doesn't have the enum val, not checking for Unknown as it will be lion @@ -273,6 +275,26 @@ void Tomahawk::enableFullscreen() NSView *nsview = (NSView *)w->winId(); NSWindow *nswindow = [nsview window]; [nswindow setCollectionBehavior:SET_LION_FULLSCREEN]; + +#ifdef LION + if ( !receiver ) + continue; + + [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillEnterFullScreenNotification + object:nswindow + queue:nil + usingBlock:^(NSNotification * note) { + NSLog(@"Became Full Screen!"); + QMetaObject::invokeMethod( receiver, "fullScreenEntered", Qt::DirectConnection ); + }]; + [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidExitFullScreenNotification + object:nswindow + queue:nil + usingBlock:^(NSNotification * note) { + NSLog(@"Left Full Screen!"); + QMetaObject::invokeMethod( receiver, "fullScreenExited", Qt::DirectConnection ); + }]; +#endif } } } From cfa63049e2c5195d2a9fa7e1cc834dc57b57f01d Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Fri, 25 May 2012 22:18:59 +0000 Subject: [PATCH 089/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 200 +++++++++++++++++++++-------------------- lang/tomahawk_bg.ts | 197 ++++++++++++++++++++-------------------- lang/tomahawk_ca.ts | 192 ++++++++++++++++++++------------------- lang/tomahawk_de.ts | 192 ++++++++++++++++++++------------------- lang/tomahawk_en.ts | 196 +++++++++++++++++++++------------------- lang/tomahawk_es.ts | 192 ++++++++++++++++++++------------------- lang/tomahawk_fr.ts | 196 +++++++++++++++++++++------------------- lang/tomahawk_ja.ts | 190 ++++++++++++++++++++------------------- lang/tomahawk_pl.ts | 190 ++++++++++++++++++++------------------- lang/tomahawk_pt_BR.ts | 190 ++++++++++++++++++++------------------- lang/tomahawk_ru.ts | 192 ++++++++++++++++++++------------------- lang/tomahawk_sv.ts | 190 ++++++++++++++++++++------------------- lang/tomahawk_tr.ts | 190 ++++++++++++++++++++------------------- lang/tomahawk_zh_CN.ts | 190 ++++++++++++++++++++------------------- lang/tomahawk_zh_TW.ts | 190 ++++++++++++++++++++------------------- 15 files changed, 1517 insertions(+), 1370 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 93fe9380b..b1ce010a4 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -134,7 +134,7 @@ connect and stream from you? ألبومات أخرى للفنان - + Other Albums by %1 ألبومات أخرى ل%1 @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. بعد إجراء مسح مجموعة أغانيك الخاصة ستجد ألبوماتك المضافة هنا. - + This collection doesn't have any recent albums. هذه المجموعة لا تحتوي على ألبومات جديدة. @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. - + This collection is currently empty. المجموعة فارغة حاليا. - + Sorry, your filter '%1' did not match any results. نتأسف، نظام الترشيح لم يجد شيئا تحت عنوان '%1'. @@ -384,7 +384,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">نتأسف!</span>&nbsp;توماهوك تحطم. يرجى أن تخبرنا عن ذلك! لقد أنشئ توماهوك تقرير عن الخطأ نيابة عنك لمساعدتنا في تحسين استقرار البرنامج في المستقبل. يمكنك إرسال هذا التقرير الأن مباشرة لمطوري توماهوك.</p></body></html> @@ -450,7 +450,7 @@ connect and stream from you? حذف الحساب - + About this Account عن هذا الحساب @@ -505,7 +505,7 @@ connect and stream from you? InfoBar - + Filter... مرشح... @@ -662,7 +662,7 @@ connect and stream from you? NewReleasesWidget - + New Releases جديد الاصدارات @@ -825,7 +825,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! هذه القائمة فارغة حاليا. أضف لها بعض الأغاني واستمتع للموسيقى! @@ -1134,7 +1134,7 @@ connect and stream from you? Listening to "%1" by %2 on "%3" and loving it! %4 - يتم الاستماع إلى "%1" من قبل %2 على "%3" وقد أحبها! %4 + إنني أستمع إلى "%1" من قبل %2 على "%3" وقد أحببتها! %4 @@ -1287,27 +1287,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &نسخ الرابط - + &Delete %1 &أحذف %1 - + &Export Playlist &تصدير قائمة الأغاني - + Save XSPF حفظ XSPF - + Playlists (*.xspf) قوائم أغاني (*.xspf) @@ -1597,22 +1597,22 @@ connect and stream from you? حذف الحساب - + %1 downloads تحميل %1 - + Online على الهواء - + Connecting... يجرى الاتصال... - + Offline خارج الهواء @@ -1626,8 +1626,8 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على لنكس. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على منصتك. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1706,28 +1706,28 @@ connect and stream from you? نقل التاريخ... - + History Incomplete. Resume تاريخ ناقص. استأنف - + Playback History Imported تم استيراد تاريخ إعادة الإستماع - - + + Failed فشلت - + Success نجاح - + Could not contact server لم أستطيع الإتصال بالخادم @@ -1735,12 +1735,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify مزامنة مع سبوتيفي (Spotify) - + + Re-enable syncing with Spotify + إعادة تمكين المزامنة مع سبوتيفي (Spotify) + + + Stop syncing with Spotify أوقف المزامنة مع سبوتيفي (Spotify) @@ -2420,92 +2425,92 @@ Try tweaking the filters for a new set of songs to play. قد هذه الإذاعة: - + Much less أقل بكثير - + Less أقل - + A bit less أقل بقليل - + Keep at current أبقه على حاله - + A bit more أكثر قليلا - + More أكثر - + Much more أكثر من ذلك بكثير - + Tempo سرعة إيقاع - + Loudness قوة الصوت - + Danceability درجة الرقص - + Energy حيوية - + Song Hotttnesss شعبية الأغنية - + Artist Hotttnesss شعبية الفنان - + Artist Familiarity ألفة الفنان - + By Description من خلال الوصف - + Enter a description أدخل الوصف - + Apply steering command طبق أوامر القيادة - + Reset all steering commands إعادة ضبط جميع أوامر القيادة @@ -2546,7 +2551,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk is playing "%1" by %2%3. - توماهوك يلعب "%1" من قبل %2%3 + توماهوك يلعب "%1" ل%2%3 @@ -2595,7 +2600,7 @@ Try tweaking the filters for a new set of songs to play. Listening to "%1" by %2 and loving it! %3 - يتم الاستماع إلى "%1" من قبل %2 وقد أحبها! %3 + إنني أستمع إلى "%1" من قبل %2 وقد أحببتها! %3 @@ -2953,7 +2958,7 @@ enter the displayed PIN number here: - + Play إستمع @@ -2973,162 +2978,167 @@ enter the displayed PIN number here: التالي - + Back إلى الوراء - + Go back one page العودة صفحة واحدة إلى الوراء - + Forward تقدم - + Go forward one page تقدم صفحة واحدة - + Global Search... بحث شامل... - - + + Check For Updates... التحقق من التحديثات... - - - + + + Connect To Peer ربط بالند - + Enter peer address: أدخل عنوان الند: - + Enter peer port: أدخل بوابة الند: - + Enter peer key: أدخل مفتاح الند: - + XSPF Error خطأ XSPF - + This is not a valid XSPF playlist. قائمة الأغاني XSPF هذه ليست صالحة. - + Failed to save tracks فشل في حفظ الأغاني - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. - + Create New Station إنشاء &قائمة أغاني جديدة - + Name: الاسم: - + New Station إذاعة جديدة - + New Playlist قائمة أغاني جديدة - + Pause تعليق - + Go &offline إذهب &خارج الهواء - + Go &online إذهب &على الهواء - + Authentication Error خطأ في المصادقة - + Error connecting to SIP: Authentication failed! خطأ في الاتصال بسيب (SIP): فشلت المصادقة! - + %1 by %2 track, artist name %1 من قبل %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ <br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>شكر لكل من: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ - + + Thanks to: + شكر لكل من: + + + About Tomahawk عن توماهوك @@ -3285,7 +3295,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. عذراً، ترشيحك "%1" لم يطابق أي نتائج. @@ -3447,27 +3457,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection سوبر كولكشن - + Combined libraries of all your online friends جمع مكاتب أصدقائك الذين على الهواء - + All available albums جميع الألبومات الجديدة - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Recently played tracks from all your friends جميع الأغاني التي استمع إليها أصدقائك مؤخرا @@ -3503,7 +3513,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts الرسوم البيانية diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 07f5e535c..7021b36e5 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -133,7 +133,7 @@ connect and stream from you? Други албуми на този артист - + Other Albums by %1 Други албуми от %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. След като бъде сканирана музикалната ти колекция, ще откриеш тук най-скоро добавените албуми. - + This collection doesn't have any recent albums. В тази колекция все още няма добавени наскоро албуми. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. След като приключи сканирането на музикалната ти колекция, ще откриеш музиката си тук. - + This collection is currently empty. Базата данни с песни е празна. - + Sorry, your filter '%1' did not match any results. Съжалявам. Твоят филтър '%1' не върна никакъв резултат. @@ -384,11 +384,8 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Извинявай!</span> Tomahawk заби. -Моля уведоми ни за този слуай! -Tomahaw създаде доклад относно това и изпращайки го, ще помогнеш за по-добрата работа на приложението за в бъдеще. -Изпрати директно до разработчиците на Tomahawk</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> + @@ -453,7 +450,7 @@ Tomahaw създаде доклад относно това и изпращай Изтрий регистрация - + About this Account Относно тази регистрация @@ -508,7 +505,7 @@ Tomahaw създаде доклад относно това и изпращай Информационно поле - + Filter... Филтър... @@ -665,7 +662,7 @@ Tomahaw създаде доклад относно това и изпращай NewReleasesWidget - + New Releases Нови албуми @@ -828,7 +825,7 @@ Tomahaw създаде доклад относно това и изпращай PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Този списък в момента е празен. Добави няколко изпълнения и се наслади на музиката! @@ -1289,27 +1286,27 @@ Tomahaw създаде доклад относно това и изпращай SourceTreeView - + &Copy Link &Копирай адресът - + &Delete %1 &Изтрий %1 - + &Export Playlist &Изнеси списък - + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -1601,22 +1598,22 @@ Tomahaw създаде доклад относно това и изпращай Премахни регистрация - + %1 downloads %1 сваляния - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -1630,7 +1627,7 @@ Tomahaw създаде доклад относно това и изпращай - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1710,28 +1707,28 @@ Tomahaw създаде доклад относно това и изпращай - + History Incomplete. Resume - + Playback History Imported - - + + Failed Неуспешно - + Success Ура! - + Could not contact server Не мога да се свържа със сървъра @@ -1739,12 +1736,17 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -2425,92 +2427,92 @@ Try tweaking the filters for a new set of songs to play. Настройки: - + Much less Много по-малко - + Less По-малко - + A bit less Малко по-малко - + Keep at current Запази - + A bit more Малко повече - + More Повече - + Much more Много повече - + Tempo Темпо - + Loudness Сила - + Danceability Танцувалност - + Energy Енергия - + Song Hotttnesss Популярност на изпълненията - + Artist Hotttnesss Популярност на изпълнителя - + Artist Familiarity Близост на изпълнителите - + By Description По описание - + Enter a description Въведи описание - + Apply steering command Приложи избраната команда - + Reset all steering commands Нулирай всички предишни настройки @@ -2958,7 +2960,7 @@ enter the displayed PIN number here: - + Play Изпълни @@ -2978,165 +2980,170 @@ enter the displayed PIN number here: Следваща - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Глобално търсене... - - + + Check For Updates... Провери за обновления... - - - + + + Connect To Peer Свържи се с друг потребител - + Enter peer address: Въведи адресът на отдалеченият потребител: - + Enter peer port: Въведи порт: - + Enter peer key: Въведи ключът за удостоверяване: - + XSPF Error XSPF Грешка - + This is not a valid XSPF playlist. Това не е валиден XSPF списък - + Failed to save tracks Не мога да запазя списъкът с песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Някои от песните в този списък нямат артист и заглавие. Те ще бъдат игнорирани. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраната песен - тя ще бъде прескочена. Моля, увери се, че са инсталирани подходящ Phonon и приставки. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Съжалявам. Има проблем с достъпа до твоето аудио устройство или избраната песен. Тя ще бъде пропусната. - + Create New Station Създай нова станция - + Name: Име: - + New Station Нова станция - + New Playlist Нов списък - + Pause Пауза - + Go &offline Излез &извън линия - + Go &online Свържи &се - + Authentication Error Грешка при удостоверяване - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 от %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Всички права запазени 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/> Благодарности на: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Относно Tomahawk @@ -3293,7 +3300,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Съжалявам, твоят филтър %1 не върна никакъв резултат. @@ -3456,28 +3463,28 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Combined libraries of all your online friends Обща колекция с всичките ми приятели на линия - + All available albums Всички налични албуми - + Recently Played Tracks Наскоро изпълени песни - + Recently played tracks from all your friends Наскоро изпълнени песни от всичките ти приятели @@ -3513,7 +3520,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Класации diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 3dcd039eb..5c9210839 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -133,7 +133,7 @@ connect and stream from you? Altres Àlbums de l'Artista - + Other Albums by %1 Altres Àlbums de %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Després d'escanejar la vostra col·lecció musical, aquí trobareu els àlbums afegits últimament. - + This collection doesn't have any recent albums. Aquesta col·lecció no té àlbums recents. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Després d'escanejar la vostra col·lecció musical, aquí trobareu les cançons afegides últimament. - + This collection is currently empty. Aquesta col·lecció es troba buida actualment. - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Esborra el Compte - + About this Account Quant a aquest compte @@ -504,7 +504,7 @@ connect and stream from you? Barra d'Informació - + Filter... Filtra... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases Nous llançaments @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Aquesta llista es troba buida. Afegiu-hi algunes cançons i gaudiu de la música! @@ -1285,27 +1285,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copia l'Enllaç - + &Delete %1 &Esborra %1 - + &Export Playlist E&xporta la Llista de Reproducció - + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -1596,22 +1596,22 @@ i emissores de ràdio basades en el vostre gust musical. Esborra el compte - + %1 downloads %1 descàrregues - + Online En Línia - + Connecting... Connectant-se... - + Offline Fora de Línia @@ -1625,7 +1625,7 @@ i emissores de ràdio basades en el vostre gust musical.
    - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1
    @@ -1705,28 +1705,28 @@ i emissores de ràdio basades en el vostre gust musical.
    - + History Incomplete. Resume - + Playback History Imported - - + + Failed Error - + Success Èxit - + Could not contact server No s'ha pogut contactar amb el servidor @@ -1734,12 +1734,17 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -2419,92 +2424,92 @@ Intenteu ajustar els filtres per reproduir noves cançons.
    Dirigeix aquesta emissora: - + Much less Molt més - + Less Menys - + A bit less Una mica menys - + Keep at current Mantingues a l'actual - + A bit more Una mica més - + More Més - + Much more Molt més - + Tempo Temps - + Loudness Volum - + Danceability Ballabilitat - + Energy Energia - + Song Hotttnesss Rellevància de Cançó - + Artist Hotttnesss Rellevància d'Artista - + Artist Familiarity Semblança amb l'artista - + By Description Per Descripció - + Enter a description Introduïu una descripció - + Apply steering command Aplica la comanda de control - + Reset all steering commands Restaura totes les comandes de control @@ -2952,7 +2957,7 @@ introduïu el PIN aquí:
    - + Play Reprodueix @@ -2972,162 +2977,167 @@ introduïu el PIN aquí:
    Següent - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Cerca Global... - - + + Check For Updates... Comprova les actualitzacions... - - - + + + Connect To Peer Connexió Remota - + Enter peer address: Introduïu l'adreça remota: - + Enter peer port: Introduïu el port remot: - + Enter peer key: Introduïu la clau remota: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. No és una llista XSPF vàlida. - + Failed to save tracks Error en desar les cançons - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunes cançons de la llista no contenen ni artista ni titol i s'han ignorat. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Hi ha un problema per accedir al dispositiu de so o a la cançó. La cançó actual s'ha saltat. Assegureu-vos que teniu un back.end de Phonon adequant i els plugins necessaris instal·lats. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Hi ha un problema per accedir al dispositiu de so o a la cançó, la cançó actual s'ha saltat. - + Create New Station Crea una Nova Emissora - + Name: Nom: - + New Station Nova Emissora - + New Playlist Nova llista de reproducció - + Pause Pausa - + Go &offline &Desconnecta't - + Go &online &Connecta't - + Authentication Error Error d'autentificació - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Gràcies a: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter i Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Quant a Tomahawk @@ -3284,7 +3294,7 @@ introduïu el PIN aquí: TrackView - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -3446,27 +3456,27 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant ViewManager - + SuperCollection SuperCol·lecció - + Combined libraries of all your online friends Biblioteques combinades de tots els amis en línia - + All available albums Tots els àlbums disponibles - + Recently Played Tracks Cançons Escoltades Recentment - + Recently played tracks from all your friends Cançons escoltades recentment pels amics @@ -3502,7 +3512,7 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant WhatsHotWidget - + Charts Llistes diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index f30d64a57..6978301f3 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -133,7 +133,7 @@ connect and stream from you? Andere Alben des Künstlers - + Other Albums by %1 Andere Alben von %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Nachdem Tomahawk deine Sammlung durchsucht hast siehst du hier deine neuesten Alben. - + This collection doesn't have any recent albums. Diese Sammlung ist leer. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Nachdem Tomahawk deine Sammlung durchsucht hat siehst du deine Lieder hier. - + This collection is currently empty. Diese Sammlung is momentan leer. - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Konto entfernen - + About this Account Über dieses Konto @@ -504,7 +504,7 @@ connect and stream from you? Infoleiste - + Filter... Filter... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases Neuerscheinungen @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Diese Playliste ist derzeit leer. Füge einige Stücke hinzu und genieße die Musik! @@ -1285,27 +1285,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiere Link - + &Delete %1 &Lösche %1 - + &Export Playlist Playliste &exportieren - + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -1593,22 +1593,22 @@ connect and stream from you? Konto entfernen - + %1 downloads %1 Downloads - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -1622,7 +1622,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1702,28 +1702,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed Fehlgeschlagen - + Success Erfolgreich - + Could not contact server Konnte den Server nicht erreichen! @@ -1731,12 +1731,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Synchronisation beenden @@ -2414,92 +2419,92 @@ Versuch die Filter anzupassen für neue Lieder. Steuere diese Station: - + Much less Viel weniger - + Less Weniger - + A bit less Etwas weniger - + Keep at current So belassen - + A bit more Etwas mehr - + More Mehr - + Much more Viel mehr - + Tempo Tempo - + Loudness Lautstärke - + Danceability Tanzbarkeit - + Energy Energie - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity Ähnlichkeit Künstler - + By Description Von der Beschreibung - + Enter a description Gib eine Beschreibung ein - + Apply steering command Steuerkommando anwenden - + Reset all steering commands Setze alle Steuerkommandos zurück @@ -2947,7 +2952,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: - + Play Abspielen @@ -2967,162 +2972,167 @@ Tomahawk auf Twitter's Website authentifiziert hast: Weiter - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Globale Suche... - - + + Check For Updates... Nach Updates suchen... - - - + + + Connect To Peer Mit anderem Tomahawk verbinden - + Enter peer address: Gib die Adresse der Gegenstelle ein: - + Enter peer port: Gib den Port der Gegenstelle ein: - + Enter peer key: Gib den Schlüssel der Gegenstelle ein: - + XSPF Error XSPF-Fehler - + This is not a valid XSPF playlist. Dies ist keine gültige XSPF-Playliste. - + Failed to save tracks Konnte Stücke nicht abspeichern - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Einige Stücke in der Playliste enthalten weder Künstler noch Titel. Diese werden ignoriert. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. Vergewisser dich, dass ein geignetes Phonon-Backend mitsamt benötigten Plugins installiert ist. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. - + Create New Station Neue Station erstellen - + Name: Name: - + New Station Neue Station - + New Playlist Neue Playliste - + Pause Pause - + Go &offline Verbindung &trennen - + Go &online &Verbindung herstellen - + Authentication Error Authentifizierungsfehler - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 von %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Danke an: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter und Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Über Tomahawk @@ -3279,7 +3289,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3436,27 +3446,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Kombinierte Sammlung all deiner Freunde - + All available albums Alle verfügbaren Alben - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3492,7 +3502,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Charts diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index ae6834e95..a293a77aa 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -134,7 +134,7 @@ connect and stream from you? Other Albums by Artist - + Other Albums by %1 Other Albums by %1 @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. This collection doesn't have any recent albums. @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. This collection is currently empty. - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -384,8 +384,8 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -450,7 +450,7 @@ connect and stream from you? Delete Account - + About this Account About this Account @@ -505,7 +505,7 @@ connect and stream from you? InfoBar - + Filter... Filter... @@ -662,7 +662,7 @@ connect and stream from you? NewReleasesWidget - + New Releases New Releases @@ -825,7 +825,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -1286,27 +1286,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copy Link - + &Delete %1 &Delete %1 - + &Export Playlist &Export Playlist - + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -1597,22 +1597,22 @@ connect and stream from you? Remove Account - + %1 downloads %1 downloads - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -1626,8 +1626,8 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1706,28 +1706,28 @@ connect and stream from you? Importing History... - + History Incomplete. Resume History Incomplete. Resume - + Playback History Imported Playback History Imported - - + + Failed Failed - + Success Success - + Could not contact server Could not contact server @@ -1735,12 +1735,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + + Re-enable syncing with Spotify + Re-enable syncing with Spotify + + + Stop syncing with Spotify Stop syncing with Spotify @@ -2420,92 +2425,92 @@ Try tweaking the filters for a new set of songs to play. Steer this station: - + Much less Much less - + Less Less - + A bit less A bit less - + Keep at current Keep at current - + A bit more A bit more - + More More - + Much more Much more - + Tempo Tempo - + Loudness Loudness - + Danceability Danceability - + Energy Energy - + Song Hotttnesss Song Hotttnesss - + Artist Hotttnesss Artist Hotttnesss - + Artist Familiarity Artist Familiarity - + By Description By Description - + Enter a description Enter a description - + Apply steering command Apply steering command - + Reset all steering commands Reset all steering commands @@ -2953,7 +2958,7 @@ enter the displayed PIN number here: - + Play Play @@ -2973,162 +2978,167 @@ enter the displayed PIN number here: Next - + Back Back - + Go back one page Go back one page - + Forward Forward - + Go forward one page Go forward one page - + Global Search... Global Search... - - + + Check For Updates... Check For Updates... - - - + + + Connect To Peer Connect To Peer - + Enter peer address: Enter peer address: - + Enter peer port: Enter peer port: - + Enter peer key: Enter peer key: - + XSPF Error XSPF Error - + This is not a valid XSPF playlist. This is not a valid XSPF playlist. - + Failed to save tracks Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Create New Station - + Name: Name: - + New Station New Station - + New Playlist New Playlist - + Pause Pause - + Go &offline Go &offline - + Go &online Go &online - + Authentication Error Authentication Error - + Error connecting to SIP: Authentication failed! Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + Copyright 2010 - 2012 - + + Thanks to: + Thanks to: + + + About Tomahawk About Tomahawk @@ -3285,7 +3295,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -3447,27 +3457,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Combined libraries of all your online friends - + All available albums All available albums - + Recently Played Tracks Recently Played Tracks - + Recently played tracks from all your friends Recently played tracks from all your friends @@ -3503,7 +3513,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Charts diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 1d9f76567..9c3728280 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -133,7 +133,7 @@ connect and stream from you? Otros álbumes por el artista - + Other Albums by %1 Otros álbumes por %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Tras haber escaneado su colección aquí encontrará los últimos álbumes añadidos. - + This collection doesn't have any recent albums. Esta colección no tiene álbumes recientes. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Tras haber escaneado su colección aquí encontrará las últimas pistas añadidas. - + This collection is currently empty. Esta colección está vacía. - + Sorry, your filter '%1' did not match any results. Tu filtro '%1' no reportó ningún resultado. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Eliminar Cuenta - + About this Account Acerca de esta Cuenta @@ -504,7 +504,7 @@ connect and stream from you? Barra de información - + Filter... Filtro... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases Últimas novedades @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reproducción está vacía. ¡Añada algunas pistas y disfrute de la música! @@ -1284,27 +1284,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copiar enlace - + &Delete %1 &Eliminar %1 - + &Export Playlist &Exportar lista de reproducción - + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -1595,22 +1595,22 @@ y estaciones basadas en sus gustos personales. Eliminar Cuenta - + %1 downloads %1 descargas - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -1624,7 +1624,7 @@ y estaciones basadas en sus gustos personales. - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1704,28 +1704,28 @@ y estaciones basadas en sus gustos personales. - + History Incomplete. Resume - + Playback History Imported - - + + Failed Fallo - + Success Éxito - + Could not contact server No se pudo contactar el servidor @@ -1733,12 +1733,17 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -2418,92 +2423,92 @@ Intente ajustar los filtros para reproducir nuevas canciones. Dirigir esta estación: - + Much less Mucho menos - + Less Menos - + A bit less Un poco menos - + Keep at current Mantener en el actual - + A bit more Un poco más - + More Más - + Much more Mucho más - + Tempo Tempo - + Loudness Volumen - + Danceability Bailabilidad - + Energy Energía - + Song Hotttnesss Popularidad de la pista - + Artist Hotttnesss Popularidad del artista - + Artist Familiarity Familiaridad del artista - + By Description Por descripción - + Enter a description Introducir una descripción - + Apply steering command Aplicar comando - + Reset all steering commands Resetear todos los comandos @@ -2951,7 +2956,7 @@ introduzca su número PIN aquí: - + Play Reproducir @@ -2971,162 +2976,167 @@ introduzca su número PIN aquí: Siguiente - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Búsqueda global... - - + + Check For Updates... Buscar actualizaciones... - - - + + + Connect To Peer Conectar a un par - + Enter peer address: Introducir dirección del par: - + Enter peer port: Introducir puerto del par: - + Enter peer key: Introducir contraseña del par: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. Esta no es una lista de reproducción XSPF válida. - + Failed to save tracks Fallo al guardar pistas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunas pistas en la lista de reproducción no contienen artista ni título. Serán ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. Asegúrese de que ha instalado un backend de Phonon adecuado y los plugins necesarios. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. - + Create New Station Crear nueva estación - + Name: Nombre: - + New Station Nueva estación - + New Playlist Nueva lista de reproducción - + Pause Pausar - + Go &offline &Desconectarse - + Go &online &Conectarse - + Authentication Error Error de autenticación - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 por %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Gracias a: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter y Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk Acerca de Tomahawk @@ -3283,7 +3293,7 @@ introduzca su número PIN aquí: TrackView - + Sorry, your filter '%1' did not match any results. Lo siento, tu filtro '%1' no ha encontrado resultados. @@ -3445,27 +3455,27 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en ViewManager - + SuperCollection SuperColección - + Combined libraries of all your online friends Bibliotecas combinadas de todos tus amigos conectados - + All available albums Todos los álbumes disponibles - + Recently Played Tracks Temas Escuchados Recientemente - + Recently played tracks from all your friends Temas escuchados recientemente por mis amigos @@ -3501,7 +3511,7 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en WhatsHotWidget - + Charts Listas de éxitos diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index fb64e581e..cc374aa65 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -134,7 +134,7 @@ se connecter et streamer depuis chez vous ? Tous les albums par cet artiste - + Other Albums by %1 Autres albums par %1 @@ -161,12 +161,12 @@ se connecter et streamer depuis chez vous ? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Après avoir scanné votre collection musicale, vous trouverez les derniers albums ajoutés ici. - + This collection doesn't have any recent albums. Cette collection n'a pas d'albums récents @@ -197,17 +197,17 @@ se connecter et streamer depuis chez vous ? ArtistView - + After you have scanned your music collection you will find your tracks right here. Après avoir scanné votre collection musicale, vous trouverez tous vos titres ici. - + This collection is currently empty. La collection est vide actuellement. - + Sorry, your filter '%1' did not match any results. Désolé, votre filtre '%1' ne correspond à aucun résultat @@ -384,8 +384,8 @@ se connecter et streamer depuis chez vous ? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Désolé !</span>&nbsp;Tomahawk a planté. Dites-nous ce qui ne va pas ! Tomahawk a créé un rapport d'erreur qui sera utile pour améliorer la stabilité des prochaines versions. Vous pouvez dès maintenant envoyer ce rapport aux développeurs de Tomahawk.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> + @@ -450,7 +450,7 @@ se connecter et streamer depuis chez vous ? Supprimer le compte - + About this Account A propos de ce compte @@ -505,7 +505,7 @@ se connecter et streamer depuis chez vous ? Barre d'information - + Filter... Filtre... @@ -662,7 +662,7 @@ se connecter et streamer depuis chez vous ? NewReleasesWidget - + New Releases Nouveautés @@ -825,7 +825,7 @@ se connecter et streamer depuis chez vous ? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! La liste de lecture est vide. Ajoutez des pistes et profitez de la musique ! @@ -1286,27 +1286,27 @@ se connecter et streamer depuis chez vous ? SourceTreeView - + &Copy Link &Copier le lien - + &Delete %1 &Supprimer %1 - + &Export Playlist &Exporter la liste de lecture - + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -1597,22 +1597,22 @@ et des stations basés sur vos goûts. Supprimer le compte - + %1 downloads %1 téléchargements - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -1626,8 +1626,8 @@ et des stations basés sur vos goûts. - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - Malheureusement, l'installatio automatique de ce script de résolution n'est pas encore possible sous Linux.<br /><br />Utilisez le bouton "Installer depuis un fichier" ci-dessus en le récupérant pour votre distribution ou en le compilant. Des instructions complémentaires sont disponibles ici : <br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + @@ -1706,28 +1706,28 @@ et des stations basés sur vos goûts. Import de l'historique - + History Incomplete. Resume Historique incomplet. Reprendre - + Playback History Imported Historique de lecture importé - - + + Failed Échec - + Success Succès - + Could not contact server Impossible de contacter le serveur @@ -1735,12 +1735,17 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -2420,92 +2425,92 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer.Direction de cette station : - + Much less Beaucoup moins - + Less Moins - + A bit less Un peu moins - + Keep at current Garder le même - + A bit more Un peu plus - + More Plus - + Much more Beaucoup plus - + Tempo Tempo - + Loudness Intensité - + Danceability Dansabilité - + Energy Energie - + Song Hotttnesss Hotttnesss du morceau - + Artist Hotttnesss Hotttnesss de l'artiste - + Artist Familiarity Familiarité de l'artiste - + By Description Par description - + Enter a description Entrer une description - + Apply steering command Appliquer la commande de direction - + Reset all steering commands Annuler les commandes de direction @@ -2953,7 +2958,7 @@ saisissez le numéro PIN ici : - + Play Lecture @@ -2973,162 +2978,167 @@ saisissez le numéro PIN ici : Suivant - + Back Retour - + Go back one page Reculer d'une page - + Forward Avancer - + Go forward one page Avancer d'une page - + Global Search... Recherche Globale... - - + + Check For Updates... Rechercher une mise à jour... - - - + + + Connect To Peer Connexion à un pair - + Enter peer address: Adresse du pair : - + Enter peer port: Port du pair : - + Enter peer key: Clé du pair : - + XSPF Error Erreur XSPF - + This is not a valid XSPF playlist. Ceci n'est pas une liste de lecture XSPF valide. - + Failed to save tracks Échec de la sauvegarde des pistes - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. - + Create New Station Créer une nouvelle station - + Name: Nom : - + New Station Nouvelle station - + New Playlist Nouvelle liste de lecture - + Pause Pause - + Go &offline Se &déconnecter - + Go &online Se c&onnecter - + Authentication Error Erreur d'authentification - + Error connecting to SIP: Authentication failed! Erreur de connexion SIP : échec de l'authentification ! - + %1 by %2 track, artist name %1 par %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Merci à : Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk A propos de Tomahawk @@ -3285,7 +3295,7 @@ saisissez le numéro PIN ici : TrackView - + Sorry, your filter '%1' did not match any results. Désolé, votre filtre '%1' ne correspond à aucun résultat @@ -3447,27 +3457,27 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Collections regroupant toutes celles de vos amis en ligne - + All available albums Tous les albums disponibles - + Recently Played Tracks Derniers titres joués - + Recently played tracks from all your friends Derniers titres joués par vos amis @@ -3503,7 +3513,7 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env WhatsHotWidget - + Charts Charts diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 0af066503..f6a4c2cda 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -133,7 +133,7 @@ connect and stream from you? - + Other Albums by %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. このコレクションは現在空です。 - + Sorry, your filter '%1' did not match any results. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? - + About this Account @@ -504,7 +504,7 @@ connect and stream from you? - + Filter... フィルター... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -1286,27 +1286,27 @@ other: %n年前 SourceTreeView - + &Copy Link リンクをコピー - + &Delete %1 - + &Export Playlist - + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -1594,22 +1594,22 @@ other: %n年前 - + %1 downloads - + Online - + Connecting... - + Offline @@ -1623,7 +1623,7 @@ other: %n年前 - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1703,28 +1703,28 @@ other: %n年前 - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1732,12 +1732,17 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2410,92 +2415,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands @@ -2942,7 +2947,7 @@ enter the displayed PIN number here: - + Play @@ -2962,162 +2967,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station 新規ステーションを作成 - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3274,7 +3284,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3431,27 +3441,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3487,7 +3497,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 3f5fdeb4d..cf494f231 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -133,7 +133,7 @@ connect and stream from you? Inne albumy artysty - + Other Albums by %1 Inne albumy %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Po zeskanowaniu swojej kolekcji muzycznej w tym miejscu znajdziesz ostatnio dodane albumy. - + This collection doesn't have any recent albums. Ta kolekcja nie zawiera żadnych nowo dodanych albumów. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Po zeskanowaniu swojej kolekcji muzycznej utwory znajdziesz w tym miejscu. - + This collection is currently empty. Ta kolekcja jest aktualnie pusta. - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie pasuje do żadnych wyników. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Usuń Konto - + About this Account @@ -504,7 +504,7 @@ connect and stream from you? Informacje - + Filter... Filtruj... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases Nowe Wydania @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Ta lista jest aktualnie pusta. Dodaj do niej trochę piosenek i ciesz się muzyką! @@ -1284,27 +1284,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiuj Link - + &Delete %1 &Usuń %1 - + &Export Playlist &Eksportuj Listę - + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -1596,22 +1596,22 @@ indywidualnego profilu gustu. Usuń Konto - + %1 downloads pobrań: %1 - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -1625,7 +1625,7 @@ indywidualnego profilu gustu. - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1705,28 +1705,28 @@ indywidualnego profilu gustu. - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1734,12 +1734,17 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2414,92 +2419,92 @@ Try tweaking the filters for a new set of songs to play. Steruj tą stacją: - + Much less Dużo mniej - + Less Mniej - + A bit less Trochę mniej - + Keep at current Pozostaw jak jest - + A bit more Trochę więcej - + More Więcej - + Much more Dużo więcej - + Tempo Tempo - + Loudness Głośność - + Danceability Taneczność - + Energy Energiczność - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity Znajomość Artysty - + By Description Po Opisie - + Enter a description Wprowadź opis - + Apply steering command Zastosuj komendę sterowania - + Reset all steering commands Zresetuj wszystkie komendy sterowania @@ -2947,7 +2952,7 @@ wprowadź pokazany numer PIN tutaj: - + Play Odtwarzaj @@ -2967,162 +2972,167 @@ wprowadź pokazany numer PIN tutaj: Następny - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Globalne Wyszukiwanie... - - + + Check For Updates... Sprawdź uaktualnienia... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error Błąd XSPF - + This is not a valid XSPF playlist. To nie jest poprawna lista XSPF. - + Failed to save tracks Nie udało się zapisać utworów - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Niektóre utwory na liście nie zawierają artysty i tytułu. Zostaną one zignorowane. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Utwórz Nową Stację - + Name: Nazwa: - + New Station Nowa stacja - + New Playlist Nowa Lista - + Pause Pauza - + Go &offline Przejdź do trybu &offline - + Go &online Przejdź do trybu &online - + Authentication Error Błąd uwierzytelniania - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 wykonawcy %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3279,7 +3289,7 @@ wprowadź pokazany numer PIN tutaj: TrackView - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie dopasował żadnych wyników. @@ -3441,27 +3451,27 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl ViewManager - + SuperCollection SuperKolekcja - + Combined libraries of all your online friends Połączone biblioteki wszystkich twoich znajomych online - + All available albums Wszystkie dostępne albumy - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3497,7 +3507,7 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl WhatsHotWidget - + Charts Listy przebojów diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 878548c70..ba8f02339 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -133,7 +133,7 @@ connect and stream from you? Outros álbuns do artista - + Other Albums by %1 Outros álbuns por %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Depois que você escanear a sua biblioteca musical você encontrará aqui o último álbum adicionado. - + This collection doesn't have any recent albums. Essa biblioteca não tem nenhum álbum recente. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Depois que você escanear a sua biblioteca musical você encontrará aqui as suas faixas. - + This collection is currently empty. Essa biblioteca está vazia. - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Excluir Conta - + About this Account @@ -504,7 +504,7 @@ connect and stream from you? Barra de informações - + Filter... Filtro... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reprodução está vazia. Adicione algumas faixas para disfrutar de uma música! @@ -1284,27 +1284,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copiar link - + &Delete %1 &Eliminar %1 - + &Export Playlist &Exportar lista de reprodução - + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -1595,22 +1595,22 @@ connect and stream from you? Remover Conta - + %1 downloads - + Online - + Connecting... Conectando... - + Offline @@ -1624,7 +1624,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1704,28 +1704,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed Falhou - + Success Sucesso - + Could not contact server @@ -1733,12 +1733,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2413,92 +2418,92 @@ Try tweaking the filters for a new set of songs to play. Conduzir essa estação: - + Much less Muito menos - + Less Menos - + A bit less Um pouco menos - + Keep at current Manter atual - + A bit more Um pouco mais - + More Mais - + Much more Muito mais - + Tempo Tempo - + Loudness Mais alto - + Danceability Habilidade de dança - + Energy Energia - + Song Hotttnesss Canções preferidas - + Artist Hotttnesss Artistas preferidos - + Artist Familiarity Familiaridade do artista - + By Description Por descrição - + Enter a description Coloque uma descrição - + Apply steering command Aplicar comando de condução - + Reset all steering commands Redefinir todos os comandos de direção @@ -2946,7 +2951,7 @@ colocar o número PIN mostrado aqui: - + Play Reporduzir @@ -2966,162 +2971,167 @@ colocar o número PIN mostrado aqui: Próximo - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Busca global... - - + + Check For Updates... Buscar atualizações... - - - + + + Connect To Peer Conectar-se ao par - + Enter peer address: Coloque o endereço do par: - + Enter peer port: Coloque a porta do par: - + Enter peer key: Coloque a chave do par: - + XSPF Error Erro de XSPF - + This is not a valid XSPF playlist. Esta não é uma lista de reprodução XSPF válida. - + Failed to save tracks Falha ao salvar faixas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algumas faixas da lista de reprodução não contem artista e título. Estas serão ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Criar uma nova estação - + Name: Nome: - + New Station Nova estação - + New Playlist Nova lista de reprodução - + Pause Pausar - + Go &offline Desc&onectar - + Go &online C&onectar - + Authentication Error Erro de autenticação - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk Sobre o Tomahawk @@ -3278,7 +3288,7 @@ colocar o número PIN mostrado aqui: TrackView - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -3440,27 +3450,27 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Todos os álbuns disponíveis - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3496,7 +3506,7 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment WhatsHotWidget - + Charts Gráficos diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 75c925bd9..c9301c4b5 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -134,7 +134,7 @@ connect and stream from you? Другие альбомы артиста - + Other Albums by %1 Другие альбомы %1 @@ -161,12 +161,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. После сканирования вашей музыкальной коллекции вы найдете свой альбомы тут. - + This collection doesn't have any recent albums. Эта коллекция не имеет последних альбомов. @@ -197,17 +197,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. После сканирования вашей музыкальной коллекции вы найдете свои песни тут. - + This collection is currently empty. Коллекция пуста. - + Sorry, your filter '%1' did not match any results. К сожалению, '%1' фильтр не найдено ни одного результата. @@ -384,7 +384,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -450,7 +450,7 @@ connect and stream from you? Удалить аккаунт - + About this Account Об этом аккаунте @@ -505,7 +505,7 @@ connect and stream from you? Информация - + Filter... Фильтр... @@ -662,7 +662,7 @@ connect and stream from you? NewReleasesWidget - + New Releases Новые релизы @@ -825,7 +825,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Этот плейлист пустой. Добавьте какие-нибудь треки и наслаждайтесь музыкой! @@ -1286,27 +1286,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Скопировать Cсылку - + &Delete %1 &Удалить %1 - + &Export Playlist &Экспорт Плейлиста - + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -1594,22 +1594,22 @@ connect and stream from you? Удалить аккаунт - + %1 downloads %1 загружено - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -1623,7 +1623,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1703,28 +1703,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed Неудача - + Success Успех - + Could not contact server Не удается связаться с сервером @@ -1732,12 +1732,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -2415,92 +2420,92 @@ Try tweaking the filters for a new set of songs to play. Управляй этой станции: - + Much less Гораздо меньше - + Less Менее - + A bit less Чуть меньше - + Keep at current Имейтся в текущих - + A bit more Немного более - + More Более - + Much more Гораздо больше - + Tempo Ритм - + Loudness - + Danceability - + Energy Мощность - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description По описанию - + Enter a description Введите описание - + Apply steering command - + Reset all steering commands @@ -2947,7 +2952,7 @@ enter the displayed PIN number here: - + Play Играть @@ -2967,162 +2972,167 @@ enter the displayed PIN number here: Следующая - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Глобальный поиск - - + + Check For Updates... Проверить обновления... - - - + + + Connect To Peer Связаться с Peer - + Enter peer address: Введите адрес узла: - + Enter peer port: Введите адрес порта: - + Enter peer key: Введите адрес ключа: - + XSPF Error Ошибка XSPF - + This is not a valid XSPF playlist. Это не является допустимым XSPF плейлистом. - + Failed to save tracks Не удалось сохранить песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Некоторые треки в плейлисте не содержат исполнителя и название. Они будут проигнорированы. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Создать новую станцию - + Name: Имя: - + New Station Новая станция - + New Playlist Новый плейлист - + Pause Пауза - + Go &offline Отключиться - + Go &online Подлючиться - + Authentication Error Ошибка авторизации - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 + - + + Thanks to: + + + + About Tomahawk О Tomahawk @@ -3279,7 +3289,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Ваш поиск '%1' недал результатов. @@ -3440,27 +3450,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Общая коллекция - + Combined libraries of all your online friends Комбинированные библиотек всех ваших друзей онлайн - + All available albums Доступные альбомы - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3496,7 +3506,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Чарты diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 01f8c5dfa..d0d829263 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -133,7 +133,7 @@ connect and stream from you? Andra album av artisten - + Other Albums by %1 Andra album av %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda album här. - + This collection doesn't have any recent albums. Den här samlingen inga nya album. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda låtar här. - + This collection is currently empty. Denna samling är tom. - + Sorry, your filter '%1' did not match any results. Tyvärr, ditt filter "%1" matchade inte några resultat. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Ta bort konto - + About this Account @@ -504,7 +504,7 @@ connect and stream from you? Inforad - + Filter... Filter... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! Denna spellista är för närvarande tom. Lägg till några spår och njut av musiken! @@ -1285,27 +1285,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiera länk - + &Delete %1 &Ta bort %1 - + &Export Playlist &Exportera spellista - + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -1593,22 +1593,22 @@ connect and stream from you? - + %1 downloads - + Online - + Connecting... - + Offline @@ -1622,7 +1622,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1702,28 +1702,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1731,12 +1731,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2409,92 +2414,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less Mycket mindre - + Less Mindre - + A bit less Lite mindre - + Keep at current - + A bit more Lite mer - + More Mer - + Much more Mycket mer - + Tempo Tempo - + Loudness Loudness - + Danceability - + Energy Energi - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description Efter beskrivning - + Enter a description Ange en beskrivning - + Apply steering command - + Reset all steering commands @@ -2941,7 +2946,7 @@ enter the displayed PIN number here: - + Play Spela upp @@ -2961,162 +2966,167 @@ enter the displayed PIN number here: Nästa - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Global sökning... - - + + Check For Updates... Leta efter uppdateringar... - - - + + + Connect To Peer Anslut till klient - + Enter peer address: Ange klientadress: - + Enter peer port: Ange klientport: - + Enter peer key: Ange klientnyckel: - + XSPF Error XSPF-fel - + This is not a valid XSPF playlist. Detta är inte en giltig XSPF-spellista. - + Failed to save tracks Misslyckades med att spara spår - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Några spår i spellistan innehåller inte någon artist och titel. De kommer att ignoreras. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Skapa ny station - + Name: Namn: - + New Station Ny station - + New Playlist Ny spellista - + Pause Paus - + Go &offline Koppla &från - + Go &online A&nslut - + Authentication Error Autentiseringsfel - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 av %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3273,7 +3283,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3430,27 +3440,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Alla tillgängliga album - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3486,7 +3496,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Topplistor diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 0345e80ea..f399404b9 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -133,7 +133,7 @@ connect and stream from you? Sanatçının Diğer Albümleri - + Other Albums by %1 Diğer %1 Albümleri @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. Müzik koleksiyonunuzu taradıktan sonra en son eklenen albümleri burada bulacaksınız. - + This collection doesn't have any recent albums. Bu koleksiyonda en son eklenen bir albüm yok. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. Müzik koleksiyonunuzu taradıktan parçalarınız tam burada bulacaksınız. - + This collection is currently empty. Bu koleksiyon şu anda boş. - + Sorry, your filter '%1' did not match any results. Üzgünüm, '%1' filtresi hiçbir sonuç getirmedi. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? Hesabı Sil - + About this Account @@ -504,7 +504,7 @@ connect and stream from you? BilgiÇubuğu - + Filter... Filtre... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -1284,27 +1284,27 @@ connect and stream from you? SourceTreeView - + &Copy Link - + &Delete %1 - + &Export Playlist - + Save XSPF - + Playlists (*.xspf) @@ -1592,22 +1592,22 @@ connect and stream from you? - + %1 downloads - + Online - + Connecting... - + Offline @@ -1621,7 +1621,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1701,28 +1701,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1730,12 +1730,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2408,92 +2413,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands @@ -2940,7 +2945,7 @@ enter the displayed PIN number here: - + Play @@ -2960,162 +2965,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3272,7 +3282,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3429,27 +3439,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3485,7 +3495,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index c04d5bd1f..ebf6de78c 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -133,7 +133,7 @@ connect and stream from you? 艺人的其他专辑 - + Other Albums by %1 %1 的其他专辑 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. 此收藏目前为空 - + Sorry, your filter '%1' did not match any results. 抱歉,你的过滤条件 '%1' 未匹配任何结果 @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? 删除账户 - + About this Account @@ -504,7 +504,7 @@ connect and stream from you? - + Filter... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -1284,27 +1284,27 @@ connect and stream from you? SourceTreeView - + &Copy Link - + &Delete %1 - + &Export Playlist - + Save XSPF - + Playlists (*.xspf) @@ -1592,22 +1592,22 @@ connect and stream from you? - + %1 downloads - + Online - + Connecting... - + Offline @@ -1621,7 +1621,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1701,28 +1701,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1730,12 +1730,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2408,92 +2413,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands @@ -2940,7 +2945,7 @@ enter the displayed PIN number here: - + Play @@ -2960,162 +2965,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3272,7 +3282,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3429,27 +3439,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3485,7 +3495,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 38331b37f..a23a7e8dd 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -133,7 +133,7 @@ connect and stream from you? 列出演出者的其他專輯 - + Other Albums by %1 列出所有其他專輯,依 %1 @@ -160,12 +160,12 @@ connect and stream from you? AlbumView - + After you have scanned your music collection you will find your latest album additions right here. 當您掃描您的音樂收藏,您會發現您的最新專輯添加在這裡。 - + This collection doesn't have any recent albums. 這個收藏沒有任何最新專輯。 @@ -196,17 +196,17 @@ connect and stream from you? ArtistView - + After you have scanned your music collection you will find your tracks right here. 當您掃描您的音樂收藏,您將在這裡找到您的曲目。 - + This collection is currently empty. 目前這個收藏是空的。 - + Sorry, your filter '%1' did not match any results. @@ -383,7 +383,7 @@ connect and stream from you? - <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send the this report directly to the Tomahawk developers.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> @@ -449,7 +449,7 @@ connect and stream from you? 刪除帳戶 - + About this Account 關於此帳戶 @@ -504,7 +504,7 @@ connect and stream from you? 信息欄 - + Filter... 過濾器... @@ -661,7 +661,7 @@ connect and stream from you? NewReleasesWidget - + New Releases 新版本 @@ -824,7 +824,7 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! 目前這個播放清單是空的。請加入一些曲目,然後盡情享受音樂! @@ -1284,27 +1284,27 @@ connect and stream from you? SourceTreeView - + &Copy Link 複製鏈接 - + &Delete %1 - + &Export Playlist 匯出播放清單 - + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -1592,22 +1592,22 @@ connect and stream from you? 刪除帳戶 - + %1 downloads - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -1621,7 +1621,7 @@ connect and stream from you? - Unfortunately, automatic installation of this resolver is not yet available on Linux.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1701,28 +1701,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed 失敗 - + Success 成功 - + Could not contact server 無法聯繫服務器 @@ -1730,12 +1730,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + + Re-enable syncing with Spotify + + + + Stop syncing with Spotify @@ -2408,92 +2413,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description 輸入一個描述 - + Apply steering command - + Reset all steering commands @@ -2940,7 +2945,7 @@ enter the displayed PIN number here: - + Play 播放 @@ -2960,162 +2965,167 @@ enter the displayed PIN number here: 下一首 - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... 全域搜尋... - - + + Check For Updates... 檢查更新... - - - + + + Connect To Peer 連接點對點 - + Enter peer address: 輸入對等地址: - + Enter peer port: 輸入對等連接埠: - + Enter peer key: 輸入對等密鑰: - + XSPF Error XSPF 錯誤 - + This is not a valid XSPF playlist. - + Failed to save tracks 無法儲存曲目 - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: 名稱: - + New Station - + New Playlist 新增播放清單 - + Pause 暫停 - + Go &offline 離線 - + Go &online 上網 - + Authentication Error 驗證錯誤 - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - - Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + Copyright 2010 - 2012 - + + Thanks to: + + + + About Tomahawk @@ -3272,7 +3282,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3430,27 +3440,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection 超級收藏 - + Combined libraries of all your online friends 聯合您所有線上朋友的音樂庫 - + All available albums 所有現有專輯 - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3486,7 +3496,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts From da82f398be96eff8dee1c4adbbbd4dfe9ff72a9c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 26 May 2012 11:13:42 +0200 Subject: [PATCH 090/433] * Fixed untranslatable strings issue. --- src/TomahawkApp.cpp | 24 ++++++++++ src/TomahawkApp.h | 1 + src/main.cpp | 111 +++++++++++++++++++------------------------- 3 files changed, 72 insertions(+), 64 deletions(-) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index f98bce7b1..d95e24840 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "Artist.h" #include "Album.h" @@ -129,6 +130,29 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) setApplicationVersion( QLatin1String( TOMAHAWK_VERSION ) ); registerMetaTypes(); + installTranslator(); +} + + +void +TomahawkApp::installTranslator() +{ + QString locale = QLocale::system().name(); + if ( locale == "C" ) + locale = "en"; + + QTranslator* translator = new QTranslator( this ); + if ( translator->load( QString( ":/lang/tomahawk_" ) + locale ) ) + { + tDebug() << "Using system locale:" << locale; + } + else + { + tDebug() << "Using default locale, system locale one not found:" << locale; + translator->load( QString( ":/lang/tomahawk_en" ) ); + } + + TOMAHAWK_APPLICATION::installTranslator( translator ); } diff --git a/src/TomahawkApp.h b/src/TomahawkApp.h index a1c6f0724..41cfae3a9 100644 --- a/src/TomahawkApp.h +++ b/src/TomahawkApp.h @@ -115,6 +115,7 @@ private slots: void accountManagerReady(); private: + void installTranslator(); void registerMetaTypes(); void printHelp(); diff --git a/src/main.cpp b/src/main.cpp index dfb01ff1c..870bded10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,8 +25,6 @@ #include "config.h" #include "utils/Logger.h" -#include - #ifdef Q_WS_MAC #include "TomahawkApp_Mac.h" #include @@ -38,50 +36,53 @@ #include "breakpad/BreakPad.h" #endif + #ifdef Q_OS_WIN // code from patch attached to QTBUG-19064 by Honglei Zhang -LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam); +LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam ); HHOOK hKeyboardHook; HINSTANCE hGuiLibInstance; -LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) +LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam ) { LPKBDLLHOOKSTRUCT kbHookStruct = reinterpret_cast(lParam); - switch(kbHookStruct->vkCode){ - case VK_VOLUME_MUTE: - case VK_VOLUME_DOWN: - case VK_VOLUME_UP: - case VK_MEDIA_NEXT_TRACK: - case VK_MEDIA_PREV_TRACK: - case VK_MEDIA_STOP: - case VK_MEDIA_PLAY_PAUSE: - case VK_LAUNCH_MEDIA_SELECT: - // send message - { - HWND hWnd = NULL; - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - // relay message to each top level widgets(window) - // if the window has focus, we don't send a duplicate message - if(QApplication::activeWindow() == widget){ - continue; + switch(kbHookStruct->vkCode) + { + case VK_VOLUME_MUTE: + case VK_VOLUME_DOWN: + case VK_VOLUME_UP: + case VK_MEDIA_NEXT_TRACK: + case VK_MEDIA_PREV_TRACK: + case VK_MEDIA_STOP: + case VK_MEDIA_PLAY_PAUSE: + case VK_LAUNCH_MEDIA_SELECT: + // send message + { + HWND hWnd = NULL; + foreach ( QWidget *widget, QApplication::topLevelWidgets() ) + { + // relay message to each top level widgets(window) + // if the window has focus, we don't send a duplicate message + if ( QApplication::activeWindow() == widget ) + continue; + + hWnd = widget->winId(); + + // generate message and post it to the message queue + LPKBDLLHOOKSTRUCT pKeyboardHookStruct = reinterpret_cast(lParam); + WPARAM _wParam = pKeyboardHookStruct->vkCode; + LPARAM _lParam = MAKELPARAM( pKeyboardHookStruct->scanCode, pKeyboardHookStruct->flags ); + PostMessage( hWnd, wParam, _wParam, _lParam ); } - - hWnd = widget->winId(); - - // generate message and post it to the message queue - LPKBDLLHOOKSTRUCT pKeyboardHookStruct = reinterpret_cast(lParam); - WPARAM _wParam = pKeyboardHookStruct->vkCode; - LPARAM _lParam = MAKELPARAM(pKeyboardHookStruct->scanCode, pKeyboardHookStruct->flags); - PostMessage(hWnd, wParam, _wParam, _lParam); } - } - break; - default: - break; + break; + + default: + break; } - return CallNextHookEx(0, nCode, wParam, lParam); + return CallNextHookEx( 0, nCode, wParam, lParam ); } #include @@ -89,32 +90,29 @@ LRESULT QT_WIN_CALLBACK qt_LowLevelKeyboardHookProc(int nCode, WPARAM wParam, LP #define argv __argv // code taken from AbiWord, (c) AbiSource Inc. -int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, - PSTR szCmdLine, int iCmdShow) +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) { hKeyboardHook = NULL; hGuiLibInstance = hInstance; - // setup keyboard hook to receive multimedia key events when application is at background - hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC) qt_LowLevelKeyboardHookProc, hGuiLibInstance, 0); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,(HOOKPROC) qt_LowLevelKeyboardHookProc, hGuiLibInstance, 0 ); - if (fileno (stdout) != -1 && _get_osfhandle (fileno (stdout)) != -1) + if ( fileno( stdout ) != -1 && _get_osfhandle( fileno( stdout ) ) != -1 ) { /* stdout is fine, presumably redirected to a file or pipe */ } else { typedef BOOL (WINAPI * AttachConsole_t) (DWORD); + AttachConsole_t p_AttachConsole = (AttachConsole_t) GetProcAddress( GetModuleHandleW( L"kernel32.dll" ), "AttachConsole" ); - AttachConsole_t p_AttachConsole = (AttachConsole_t) GetProcAddress (GetModuleHandleW(L"kernel32.dll"), "AttachConsole"); - - if (p_AttachConsole != NULL && p_AttachConsole (ATTACH_PARENT_PROCESS)) + if ( p_AttachConsole != NULL && p_AttachConsole( ATTACH_PARENT_PROCESS ) ) { - _wfreopen (L"CONOUT$", L"w", stdout); - dup2 (fileno (stdout), 1); - _wfreopen (L"CONOUT$", L"w", stderr); - dup2 (fileno (stderr), 2); + _wfreopen ( L"CONOUT$", L"w", stdout ); + dup2( fileno( stdout ), 1 ); + _wfreopen ( L"CONOUT$", L"w", stderr ); + dup2( fileno( stderr ), 2 ); } } #else // Q_OS_WIN @@ -145,7 +143,6 @@ main( int argc, char *argv[] ) new TomahawkSettingsGui( &a ); #endif - #ifndef ENABLE_HEADLESSs #ifdef WITH_BREAKPAD new BreakPad( QDir::tempPath(), TomahawkSettings::instance()->crashReporterEnabled() ); @@ -158,21 +155,6 @@ main( int argc, char *argv[] ) if ( guard.isPrimaryInstance() ) a.init(); - QString locale = QLocale::system().name(); - if ( locale == "C" ) - locale = "en"; - QTranslator translator; - if ( translator.load( QString( ":/lang/tomahawk_" ) + locale ) ) - { - tDebug() << "Using system locale:" << locale; - } - else - { - tDebug() << "Using default locale, system locale one not found:" << locale; - translator.load( QString( ":/lang/tomahawk_en" ) ); - } - a.installTranslator( &translator ); - if ( argc > 1 ) { QString arg = a.arguments()[ 1 ]; @@ -182,12 +164,13 @@ main( int argc, char *argv[] ) int returnCode = a.exec(); #ifdef Q_OS_WIN // clean up keyboard hook - if( hKeyboardHook ) + if ( hKeyboardHook ) { - UnhookWindowsHookEx(hKeyboardHook); + UnhookWindowsHookEx( hKeyboardHook ); hKeyboardHook = NULL; } #endif + return returnCode; } From d846c8a693c6622d221dc1745018d2c65877685d Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 26 May 2012 09:12:11 -0400 Subject: [PATCH 091/433] Fix ported from ResolverAccount to CustomAtticaAccount omission --- src/accounts/spotify/SpotifyAccount.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/accounts/spotify/SpotifyAccount.cpp index 16b9e22a0..5f4add6ec 100644 --- a/src/accounts/spotify/SpotifyAccount.cpp +++ b/src/accounts/spotify/SpotifyAccount.cpp @@ -88,6 +88,12 @@ SpotifyAccount::SpotifyAccount( const QString& accountId ) SpotifyAccount::~SpotifyAccount() { clearUser(); + + if ( m_spotifyResolver.isNull() ) + return; + + Pipeline::instance()->removeScriptResolver( m_spotifyResolver.data()->filePath() ); + delete m_spotifyResolver.data(); } From bd9a1aab8e1a5f6f9d4a7341ff6da464d2419ec2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 26 May 2012 17:20:04 +0200 Subject: [PATCH 092/433] * Fixed un-tr()'d strings. --- src/sourcetree/SourceTreeView.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index c73853c92..b6552c48d 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -190,13 +190,13 @@ SourceTreeView::setupMenus() QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); - QString addToText = QString( "Add to my %1" ); + QString addToText = tr( "Add to my %1" ); if ( type == SourcesModel::StaticPlaylist ) - addToText = addToText.arg( "playlists" ); + addToText = addToText.arg( tr( "playlists" ) ); if ( type == SourcesModel::AutomaticPlaylist ) - addToText = addToText.arg( "Automatic Playlists" ); + addToText = addToText.arg( tr( "Automatic Playlists" ) ); else if ( type == SourcesModel::Station ) - addToText = addToText.arg( "Stations" ); + addToText = addToText.arg( tr( "Stations" ) ); QAction *addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) ); @@ -226,7 +226,6 @@ SourceTreeView::setupMenus() } } - if ( type == SourcesModel::StaticPlaylist ) copyPlaylistAction->setText( tr( "&Export Playlist" ) ); From 9f7c6b23806e7cfa07b3a19ce2c33a7683fa4260 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 26 May 2012 17:26:56 +0200 Subject: [PATCH 093/433] * Made strings translation-friendlier for various languages. --- src/sourcetree/SourceTreeView.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index b6552c48d..586fd21a3 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -190,13 +190,13 @@ SourceTreeView::setupMenus() QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); - QString addToText = tr( "Add to my %1" ); + QString addToText; if ( type == SourcesModel::StaticPlaylist ) - addToText = addToText.arg( tr( "playlists" ) ); + addToText = tr( "Add to my Playlists" ); if ( type == SourcesModel::AutomaticPlaylist ) - addToText = addToText.arg( tr( "Automatic Playlists" ) ); + addToText = tr( "Add to my Automatic Playlists" ); else if ( type == SourcesModel::Station ) - addToText = addToText.arg( tr( "Stations" ) ); + addToText = tr( "Add to my Stations" ); QAction *addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) ); From a55c1c0f08c5a858317b33f21ad72528a68589df Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sat, 26 May 2012 15:31:06 +0000 Subject: [PATCH 094/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 34 +++++++-- lang/tomahawk_bg.ts | 102 ++++++++++++++++---------- lang/tomahawk_ca.ts | 34 +++++++-- lang/tomahawk_de.ts | 38 +++++++--- lang/tomahawk_en.ts | 34 +++++++-- lang/tomahawk_es.ts | 34 +++++++-- lang/tomahawk_fr.ts | 34 +++++++-- lang/tomahawk_ja.ts | 161 ++++++++++++++++++++++++----------------- lang/tomahawk_pl.ts | 34 +++++++-- lang/tomahawk_pt_BR.ts | 34 +++++++-- lang/tomahawk_ru.ts | 34 +++++++-- lang/tomahawk_sv.ts | 34 +++++++-- lang/tomahawk_tr.ts | 34 +++++++-- lang/tomahawk_zh_CN.ts | 34 +++++++-- lang/tomahawk_zh_TW.ts | 34 +++++++-- 15 files changed, 510 insertions(+), 199 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index b1ce010a4..8a53d6149 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -1297,17 +1297,37 @@ connect and stream from you? &أحذف %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &تصدير قائمة الأغاني - + Save XSPF حفظ XSPF - + Playlists (*.xspf) قوائم أغاني (*.xspf) @@ -1735,17 +1755,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify مزامنة مع سبوتيفي (Spotify) - + Re-enable syncing with Spotify إعادة تمكين المزامنة مع سبوتيفي (Spotify) - + Stop syncing with Spotify أوقف المزامنة مع سبوتيفي (Spotify) @@ -2760,7 +2780,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection مجموعتي الخاصة diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 7021b36e5..18fbaf1cb 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -385,7 +385,10 @@ connect and stream from you? <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Извинявай!</span> Tomahawk заби. +Моля уведоми ни за този слуай! +Tomahaw създаде доклад относно това и изпращайки го, ще помогнеш за по-добрата работа на приложението за в бъдеще. +Изпрати директно до разработчиците на Tomahawk</p></body></html> @@ -558,7 +561,7 @@ connect and stream from you? Import Playback History - + Импортирай история на просвирените песни @@ -672,62 +675,62 @@ connect and stream from you? Artist - + Артист Title - + Име Composer - + Композитор Album - + Албум Track - + Песен Duration - + Продължителност Bitrate - + Качество Age - + Възраст Year - + Година Size - + Големина Origin - + Източник Score - + Резултат @@ -1296,17 +1299,37 @@ connect and stream from you? &Изтрий %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Изнеси списък - + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -1628,7 +1651,10 @@ connect and stream from you? Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + За съжаление, автоматичното инсталиране на този компонен е деактивирано за твоята платформа. +<br /><br /> +Моля използвай опцията 'Инсталирай от файл', намираща се по-горе. За целта е необходимо предварително да изтеглиш необходимите файлове за твоята платформа и да ги компилираш самостоятелно. +Допълнителни инструкции могат да бъдат открити на <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1688,7 +1714,7 @@ connect and stream from you? Testing... - + Тествам... @@ -1699,22 +1725,22 @@ connect and stream from you? Importing %1 e.g. Importing 2012/01/01 - + Импортирам %1 Importing History... - + Импортирам... History Incomplete. Resume - + Непълна информация. Продължи. Playback History Imported - + Историята на просвирените песни е импортирана @@ -1736,17 +1762,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + Re-enable syncing with Spotify - + Включи отново синхронизирането със Spotify - + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -1985,7 +2011,7 @@ You may wish to try re-authenticating. &Show Track Page - + &Покажи страницата на песента @@ -1995,12 +2021,12 @@ You may wish to try re-authenticating. &Show Album Page - + &Покажи страницата на албума &Show Artist Page - + &Покажи страницата на артистът @@ -2762,7 +2788,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция @@ -2987,17 +3013,17 @@ enter the displayed PIN number here: Go back one page - + Една страница назад Forward - + Напред Go forward one page - + Една страница напред @@ -3108,7 +3134,7 @@ enter the displayed PIN number here: Error connecting to SIP: Authentication failed! - + Грешка при свързване: Неуспешно удостоверяване! @@ -3135,12 +3161,12 @@ enter the displayed PIN number here: Copyright 2010 - 2012 - + Всички права - запазени. 2010 - 2012 Thanks to: - + Благодарности на: @@ -3264,7 +3290,7 @@ enter the displayed PIN number here: Lyrics - + Текст diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 5c9210839..710aa68ab 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -1295,17 +1295,37 @@ connect and stream from you? &Esborra %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist E&xporta la Llista de Reproducció - + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -1734,17 +1754,17 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -2759,7 +2779,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. TomahawkApp - + My Collection La meva Col·lecció diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 6978301f3..c8d777e76 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -944,7 +944,7 @@ connect and stream from you? %1 minutes ago - vor %1 Minute + vor %1 Minuten @@ -1295,17 +1295,37 @@ connect and stream from you? &Lösche %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist Playliste &exportieren - + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -1731,17 +1751,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + Re-enable syncing with Spotify - + Stop syncing with Spotify Synchronisation beenden @@ -2373,7 +2393,7 @@ Versuch die Filter anzupassen für neue Lieder. about %n minute(s) long - ungefähr %n Minute langungefähr %n Minuten lang + ungefähr eine Minute langungefähr %n Minuten lang @@ -2754,7 +2774,7 @@ Versuch die Filter anzupassen für neue Lieder. TomahawkApp - + My Collection Meine Sammlung diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index a293a77aa..d9431f6e1 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -1296,17 +1296,37 @@ connect and stream from you? &Delete %1 - + + Add to my %1 + Add to my %1 + + + + playlists + playlists + + + + Automatic Playlists + Automatic Playlists + + + + Stations + Stations + + + &Export Playlist &Export Playlist - + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -1735,17 +1755,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + Re-enable syncing with Spotify Re-enable syncing with Spotify - + Stop syncing with Spotify Stop syncing with Spotify @@ -2760,7 +2780,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection My Collection diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 9c3728280..b49071480 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -1294,17 +1294,37 @@ connect and stream from you? &Eliminar %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Exportar lista de reproducción - + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -1733,17 +1753,17 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -2758,7 +2778,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. TomahawkApp - + My Collection Mi colección diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index cc374aa65..2c2ac0997 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -1296,17 +1296,37 @@ se connecter et streamer depuis chez vous ? &Supprimer %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Exporter la liste de lecture - + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -1735,17 +1755,17 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -2760,7 +2780,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. TomahawkApp - + My Collection Ma Collection diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index f6a4c2cda..069b688c1 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -71,13 +71,13 @@ connect and stream from you? &Listen Privately - + 非公開で聴く &Listen Publicly - + 公開で聴く @@ -107,12 +107,12 @@ connect and stream from you? &Previous Track - + 前のトラック &Next Track - + 次のトラック @@ -125,17 +125,17 @@ connect and stream from you? Form - + フォーム Other Albums by Artist - + 他のアルバム Other Albums by %1 - + %1の他のアルバム @@ -149,7 +149,7 @@ connect and stream from you? All albums from %1 - + %1のすべてのアルバム @@ -162,12 +162,12 @@ connect and stream from you? After you have scanned your music collection you will find your latest album additions right here. - + コレクションをスキャンした後、最近追加したアルバムがここに表示されます。 This collection doesn't have any recent albums. - + 最近追加したアルバムはありません。 @@ -175,7 +175,7 @@ connect and stream from you? Form - + フォーム @@ -198,7 +198,7 @@ connect and stream from you? After you have scanned your music collection you will find your tracks right here. - + コレクションをスキャンした後、最近追加したトラックがここに表示されます。 @@ -208,7 +208,7 @@ connect and stream from you? Sorry, your filter '%1' did not match any results. - + '%1'に一致する情報は見つかりませんでした。 @@ -281,12 +281,12 @@ connect and stream from you? Low - + High - + @@ -310,7 +310,7 @@ connect and stream from you? %1 Station - + %1 ステーション @@ -339,7 +339,7 @@ connect and stream from you? My Collection - + マイ コレクション @@ -379,7 +379,7 @@ connect and stream from you? Tomahawk Crash Reporter - + Tomahawkの問題のレポート @@ -409,7 +409,7 @@ connect and stream from you? Uploaded %L1 of %L2 KB. - + %L1/%L2 KB アップロード完了 @@ -420,12 +420,12 @@ connect and stream from you? Sent! <b>Many thanks</b>. - + 送信完了! <b>ありがとうございます!</b> Failed to send crash info. - + クラッシュ情報の送信に失敗しました。 @@ -446,7 +446,7 @@ connect and stream from you? Delete Account - + アカウントを削除 @@ -459,7 +459,7 @@ connect and stream from you? Tomahawk Diagnostics - + Tomahawkの診断 @@ -477,7 +477,7 @@ connect and stream from you? No tracks found for given %1 - + %1 に該当するトラックは見つかりませんでした。 @@ -485,7 +485,7 @@ connect and stream from you? Form - + フォーム @@ -493,7 +493,7 @@ connect and stream from you? Indexing database - + データベースのインデックスを作成中 @@ -532,12 +532,12 @@ connect and stream from you? Form - + フォーム Scrobble tracks to Last.fm - + Last.fmにトラックをscrobbleする @@ -552,7 +552,7 @@ connect and stream from you? Test Login - + ログインを確認する @@ -573,7 +573,7 @@ connect and stream from you? %1 is listening along to you! - + %1と一緒に聴いています! @@ -609,12 +609,12 @@ connect and stream from you? Load XSPF File - + XSPFファイルを読み込む XSPF Files (*.xspf) - + XSPFファイル (*.xspf) @@ -627,7 +627,7 @@ connect and stream from you? Saved tracks - + トラックを保存する @@ -635,17 +635,17 @@ connect and stream from you? Enter a title for the new playlist: - + 新規プレイリストのタイトルを入力: Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! - + Tomahawkは新規プレイリストを作成したり、好きな曲を見つける様々な方法を提供しています! Just enter a genre or tag name and Tomahawk will suggest a few songs to get you started with your new playlist: - + ジャンルやタグ名を入力すると、Tomahawkが新しいプレイリストに曲を推薦します: @@ -734,12 +734,12 @@ connect and stream from you? played %1 by you - + %1を再生しました。 played %1 by %2 - + %2が%1を再生しました。 @@ -747,17 +747,17 @@ connect and stream from you? played %1 by you - + %1を再生しました。 played %1 by %2 - + %2が%1を再生しました。 added %1 - + %1を追加しました。 @@ -765,22 +765,22 @@ connect and stream from you? A playlist by %1, created %2 - + %2に作成した%1のプレイリスト you - + あなた All tracks by %1 on album %2 - + %1のアルバム%2のトラック All tracks by %1 - + %1のトラック @@ -808,17 +808,17 @@ connect and stream from you? New Playlist... - + 新規プレイリスト... Create Manual Playlist - + 自分でプレイリストを作成する Create Automatic Playlist - + 自動でプレイリストを作成する @@ -826,7 +826,7 @@ connect and stream from you? This playlist is currently empty. Add some tracks to it and enjoy the music! - + プレイリストには何も入っていません。トラックを追加して、音楽を楽しみましょう! @@ -839,7 +839,7 @@ connect and stream from you? Hostname of proxy server - + プロキシサーバのホスト @@ -854,38 +854,39 @@ connect and stream from you? Proxy login - + プロキシのログインネーム User - + ユーザー Password - + パスワード Proxy password - + プロキシのパスワード No Proxy Hosts: (Overrides system proxy) - + 優先プロキシ: +(システムプロキシより優先されます) localhost *.example.com (space separated) - + localhost *.example.com (スペースで区切られます) Use proxy for DNS lookups? - + 正引きDNSにプロキシを使用しますか? @@ -900,22 +901,26 @@ other: %n年前 %n year(s) - + one: %n年 +other: %n年 %n month(s) ago - + one: %nヶ月前 +other: %nヶ月前 %n month(s) - + one: %nヶ月 +other: %nヶ月 %n week(s) ago - + one: %n週間前 +other: %n週間前 @@ -1296,17 +1301,37 @@ other: %n年前 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist - + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -1732,17 +1757,17 @@ other: %n年前 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2750,7 +2775,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index cf494f231..28d3712d7 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -1294,17 +1294,37 @@ connect and stream from you? &Usuń %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Eksportuj Listę - + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -1734,17 +1754,17 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2754,7 +2774,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index ba8f02339..7bac525f6 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -1294,17 +1294,37 @@ connect and stream from you? &Eliminar %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Exportar lista de reprodução - + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -1733,17 +1753,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2753,7 +2773,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index c9301c4b5..9853b3232 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -1296,17 +1296,37 @@ connect and stream from you? &Удалить %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Экспорт Плейлиста - + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -1732,17 +1752,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -2755,7 +2775,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index d0d829263..39726789c 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1295,17 +1295,37 @@ connect and stream from you? &Ta bort %1 - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist &Exportera spellista - + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -1731,17 +1751,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2749,7 +2769,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index f399404b9..0cb71e79c 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -1294,17 +1294,37 @@ connect and stream from you? - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist - + Save XSPF - + Playlists (*.xspf) @@ -1730,17 +1750,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2748,7 +2768,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index ebf6de78c..41342730b 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -1294,17 +1294,37 @@ connect and stream from you? - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist - + Save XSPF - + Playlists (*.xspf) @@ -1730,17 +1750,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2748,7 +2768,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index a23a7e8dd..f1362e420 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -1294,17 +1294,37 @@ connect and stream from you? - + + Add to my %1 + + + + + playlists + + + + + Automatic Playlists + + + + + Stations + + + + &Export Playlist 匯出播放清單 - + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -1730,17 +1750,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -2748,7 +2768,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection 我的收藏 From ecd4aeb9656aab11071b917a80bdd99163bcd17a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 26 May 2012 18:07:50 +0200 Subject: [PATCH 095/433] * Make the hover fade a bit more noticeable. Looks nice imo. --- src/libtomahawk/playlist/AlbumItemDelegate.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index 0f262f44e..d1f6419df 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -44,7 +44,7 @@ #include "utils/Logger.h" namespace { - static const int FADE_DURATION = 75; + static const int FADE_DURATION = 250; }; @@ -125,10 +125,8 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, fader->setSize( r.size() ); const QPixmap cover = fader->currentPixmap(); - painter->drawPixmap( r, cover ); - qreal opacity = -1.; if ( m_hoverFaders.contains( index ) ) { @@ -140,7 +138,6 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, opacity = 0.35; } - if ( opacity > -1. ) { painter->save(); From 5e820ee0a8e1711ccbef2b591358807facacefbf Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 26 May 2012 18:17:46 +0200 Subject: [PATCH 096/433] * Fixed broken translation. --- src/sourcetree/SourceTreeView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index 586fd21a3..5313bab85 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -198,7 +198,7 @@ SourceTreeView::setupMenus() else if ( type == SourcesModel::Station ) addToText = tr( "Add to my Stations" ); - QAction *addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) ); + QAction *addToLocalAction = m_roPlaylistMenu.addAction( addToText ); m_roPlaylistMenu.addAction( copyPlaylistAction ); deletePlaylistAction->setEnabled( !readonly ); From 23ef32ffeedc7f7fffbd1ec78b9f451b490f2d2e Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sat, 26 May 2012 22:16:57 +0000 Subject: [PATCH 097/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 57 +++++++++++++++++++----------------------- lang/tomahawk_bg.ts | 11 +++----- lang/tomahawk_ca.ts | 11 +++----- lang/tomahawk_de.ts | 57 +++++++++++++++++++----------------------- lang/tomahawk_en.ts | 17 +++++-------- lang/tomahawk_es.ts | 11 +++----- lang/tomahawk_fr.ts | 11 +++----- lang/tomahawk_ja.ts | 11 +++----- lang/tomahawk_pl.ts | 11 +++----- lang/tomahawk_pt_BR.ts | 11 +++----- lang/tomahawk_ru.ts | 11 +++----- lang/tomahawk_sv.ts | 11 +++----- lang/tomahawk_tr.ts | 11 +++----- lang/tomahawk_zh_CN.ts | 11 +++----- lang/tomahawk_zh_TW.ts | 11 +++----- 15 files changed, 94 insertions(+), 169 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 8a53d6149..7b81883a0 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -410,7 +410,7 @@ connect and stream from you? Uploaded %L1 of %L2 KB. - تحميل %L1 من أصل %L2 كب + تحميل %L1 من أصل %L2 كب. @@ -819,7 +819,7 @@ connect and stream from you? Create Automatic Playlist - إنشاء قائمة أغاني جديدة تلقائيا + إنشاء قائمة أغاني جديدة أوتوماتيكيا @@ -1296,25 +1296,20 @@ connect and stream from you? &Delete %1 &أحذف %1 - - - Add to my %1 - - - playlists - + Add to my Playlists + أضف إلى لوائحي للأغاني - Automatic Playlists - + Add to my Automatic Playlists + أضف إلى لوائحي الأوتوماتيكية للأغاني - Stations - + Add to my Stations + أضف إلى إذاعاتي @@ -1920,7 +1915,7 @@ You may wish to try re-authenticating. Tweeted! - ثبت التويت (!Tweeted) + ثبت التويت! (!Tweeted) @@ -1943,7 +1938,7 @@ You may wish to try re-authenticating. Log on to your Jabber/XMPP account to connect to your friends - أدخل إلى حسابك على Jabber/XMPP للربط بأصدقائك. + أدخل إلى حسابك على Jabber/XMPP للربط بأصدقائك @@ -1951,7 +1946,7 @@ You may wish to try re-authenticating. Automatically connect to Tomahawks on the local network - أربط نفسك بتوماهاوك على الشبكة المحلية بطريقة مباشرة + أربط نفسك بتوماهاوك على الشبكة المحلية بطريقة مباشرة أوتوماتيكيا @@ -2156,7 +2151,7 @@ Try tweaking the filters for a new set of songs to play. No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings - لا يوجد مستخدمين مع فهرس "Echo Nest" ممكن. تجربة تمكين خيار المجموعة في الإعدادات يمكن أن يساعد. + لا يوجد مستخدمين مع فهرس "Echo Nest" ممكن. تجربة تمكين خيار المجموعة في الإعدادات يمكن أن يساعد @@ -2571,7 +2566,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk is playing "%1" by %2%3. - توماهوك يلعب "%1" ل%2%3 + توماهوك يلعب "%1" ل%2%3. @@ -2670,7 +2665,7 @@ Try tweaking the filters for a new set of songs to play. &Listen Along - تابع الاستماع + &تابع الاستماع @@ -2774,7 +2769,7 @@ Try tweaking the filters for a new set of songs to play. Automatically update from XSPF - تحديث تلقائي من XSPF + تحديث تلقائي (أوتوماتيكيا) من XSPF @@ -2849,7 +2844,7 @@ enter the displayed PIN number here: &Settings - إعدادات + &إعدادات @@ -2914,7 +2909,7 @@ enter the displayed PIN number here: Create &New Playlist... - إنشاء &قائمة أغاني جديدة + إنشاء &قائمة أغاني جديدة... @@ -2924,7 +2919,7 @@ enter the displayed PIN number here: Create New &Automatic Playlist - إنشاء &قائمة أغاني جديدة أوتوماتيكيا + إنشاء قائمة أغاني جديدة أ&وتوماتيكيا @@ -3083,7 +3078,7 @@ enter the displayed PIN number here: Create New Station - إنشاء &قائمة أغاني جديدة + إنشاء قائمة أغاني جديدة @@ -3289,7 +3284,7 @@ enter the displayed PIN number here: You've listened to this track %n time(s). - لقد استمعت إلى هذه الأغنية %n مرةلقد استمعت إلى هذه الأغنية مرة %nلقد استمعت إلى هذه الأغنية مرتين %nلقد استمعت إلى هذه الأغنية %n مراتلقد استمعت إلى هذه الأغنية %n مراتلقد استمعت إلى هذه الأغنية %n مرات + لقد استمعت إلى هذه الأغنية %n مرة.لقد استمعت إلى هذه الأغنية مرة %n.لقد استمعت إلى هذه الأغنية مرتين %n.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات. @@ -3299,12 +3294,12 @@ enter the displayed PIN number here: You first listened to it on %1. - استمعت إليها أولاً في %1 + استمعت إليها أولاً في %1. You've listened to %1 %n time(s). - لقد استمعت إلى %1 %n مرةلقد استمعت إلى %1 مرة %nلقد استمعت إلى %1 مرتين %nلقد استمعت إلى %1 %n مراتلقد استمعت إلى %1 %n مراتلقد استمعت إلى %1 %n مرات + لقد استمعت إلى %1 %n مرة.لقد استمعت إلى %1 مرة %n.لقد استمعت إلى %1 مرتين %n.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات. @@ -3558,7 +3553,7 @@ Terms for %1: No terms found, sorry. - لا شروط موجودة، نتأسف + لا شروط موجودة، نتأسف. @@ -3602,7 +3597,7 @@ Lyrics for "%1" by %2: Some playlist entries were found without artist and track name, they will be omitted - تم العثور على مداخل في قوائم الأغاني لا تحتوي على إسم فنان أو إسم أغنية، هذه المداخل سوف تحذف. + تم العثور على مداخل في قوائم الأغاني لا تحتوي على إسم فنان أو إسم أغنية، هذه المداخل سوف تحذف @@ -3744,7 +3739,7 @@ Lyrics for "%1" by %2: Server: - خادم" + خادم: @@ -3890,7 +3885,7 @@ Lyrics for "%1" by %2: This plugin will automatically find other users running Tomahawk on your local network - هذا المساعد سيجد مستخدمين أخرين لتوماهاوك على الشبكة المحلية + هذا المساعد سيجد مستخدمين أخرين لتوماهاوك على الشبكة المحلية أوتوماتيكيا diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 18fbaf1cb..25d122339 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -1298,24 +1298,19 @@ Tomahaw създаде доклад относно това и изпращай &Delete %1 &Изтрий %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 710aa68ab..626df66fb 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -1294,24 +1294,19 @@ connect and stream from you? &Delete %1 &Esborra %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index c8d777e76..885639a56 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -389,12 +389,12 @@ connect and stream from you? Send this report - + Report abschicken Don't send - + Nicht abschicken @@ -671,7 +671,7 @@ connect and stream from you? Artist - + Künstler @@ -1259,27 +1259,27 @@ connect and stream from you? Latest additions to your collection - + Neueste Lieder in deiner Sammlung Latest additions to %1's collection - + Neueste Lieder in %1's Sammlung Recently Played Tracks - + Zuletzt gehörte Lieder Your recently played tracks - + Deine zuletzt gehörten Lieder %1's recently played tracks - + %1's zuletzt gehörte Lieder @@ -1294,25 +1294,20 @@ connect and stream from you? &Delete %1 &Lösche %1 - - - Add to my %1 - - - playlists - + Add to my Playlists + Zu meinen Playlisten hinzufügen - Automatic Playlists - + Add to my Automatic Playlists + Zu meinen Automatischen Playlisten hinzufügen - Stations - + Add to my Stations + Zu meinen Stationen hinzufügen @@ -1638,7 +1633,7 @@ connect and stream from you? Manual Install Required - + Manuelle Installation benötigt @@ -2994,22 +2989,22 @@ Tomahawk auf Twitter's Website authentifiziert hast: Back - + Zurück Go back one page - + Gehe eine Seite zurück Forward - + Vorwärts Go forward one page - + Gehe eine Seite vorwärts @@ -3273,7 +3268,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: Lyrics - + Liedtext @@ -3288,22 +3283,22 @@ Tomahawk auf Twitter's Website authentifiziert hast: You've never listened to this track before. - + Du hast dieses Lied noch nie angehört. You first listened to it on %1. - + Du hast dieses Lied zum ersten mal am %1 gehört. You've listened to %1 %n time(s). - + Du hast %1 einmal angehört.Du hast %1 %n mal angehört. You've never listened to %1 before. - + Du hast %1 vorher noch nie gehört. @@ -3483,12 +3478,12 @@ You can re-send a sync message at any time simply by sending another tweet using Recently Played Tracks - + Zuletzt gehörte Lieder Recently played tracks from all your friends - + Zuletzt gehörte Lieder all deiner Freunde diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index d9431f6e1..8b209d8a8 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -1295,25 +1295,20 @@ connect and stream from you? &Delete %1 &Delete %1 - - - Add to my %1 - Add to my %1 - - playlists - playlists + Add to my Playlists + Add to my Playlists - Automatic Playlists - Automatic Playlists + Add to my Automatic Playlists + Add to my Automatic Playlists - Stations - Stations + Add to my Stations + Add to my Stations diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index b49071480..d38dfd11a 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -1293,24 +1293,19 @@ connect and stream from you? &Delete %1 &Eliminar %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 2c2ac0997..e65bf897f 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -1295,24 +1295,19 @@ se connecter et streamer depuis chez vous ? &Delete %1 &Supprimer %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 069b688c1..540692745 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -1300,24 +1300,19 @@ other: %n週間前 &Delete %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 28d3712d7..667212a20 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -1293,24 +1293,19 @@ connect and stream from you? &Delete %1 &Usuń %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 7bac525f6..fdbd225ce 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -1293,24 +1293,19 @@ connect and stream from you? &Delete %1 &Eliminar %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 9853b3232..16b5860b4 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -1295,24 +1295,19 @@ connect and stream from you? &Delete %1 &Удалить %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 39726789c..1bc76af39 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1294,24 +1294,19 @@ connect and stream from you? &Delete %1 &Ta bort %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 0cb71e79c..624f042e5 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -1293,24 +1293,19 @@ connect and stream from you? &Delete %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 41342730b..91e48c9d7 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -1293,24 +1293,19 @@ connect and stream from you? &Delete %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index f1362e420..e426bff31 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -1293,24 +1293,19 @@ connect and stream from you? &Delete %1 - - - Add to my %1 - - - playlists + Add to my Playlists - Automatic Playlists + Add to my Automatic Playlists - Stations + Add to my Stations From ae958cb12415458dc29bf7a8c440fa048c31ca7c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 26 May 2012 18:35:02 -0400 Subject: [PATCH 098/433] Don't wordwrap download count --- src/AccountDelegate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AccountDelegate.cpp b/src/AccountDelegate.cpp index 77eb60bfe..7715bd003 100644 --- a/src/AccountDelegate.cpp +++ b/src/AccountDelegate.cpp @@ -389,7 +389,7 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const int countW = painter->fontMetrics().width( count ); const QRect countRect( runningEdge + 50, starsTop, countW, painter->fontMetrics().height() ); count = painter->fontMetrics().elidedText( count, Qt::ElideRight, rightEdge - PADDING - countRect.left() ); - painter->drawText( countRect, Qt::AlignLeft | Qt::TextWordWrap, count ); + painter->drawText( countRect, Qt::AlignLeft, count ); // runningEdge = authorRect.x(); } From 05ea3065f899faeae946157326e0724838180e26 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 26 May 2012 18:35:12 -0400 Subject: [PATCH 099/433] Allow rating custom resolvers --- src/libtomahawk/accounts/AccountModel.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 61ae6e71e..2f263b9ac 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -559,18 +559,22 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role // We only support rating Attica resolvers for the moment. Attica::Content content; if ( node->type == AccountModelNode::AtticaType ) + { content = node->atticaContent; + + AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( content ); + // For now only allow rating if a resolver is installed! + if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade ) + return false; + } // Allow rating custom attica accounts regardless as user may have installed manually else if ( node->type == AccountModelNode::CustomAccountType && qobject_cast< CustomAtticaAccount* >( node->customAccount ) ) content = qobject_cast< CustomAtticaAccount* >( node->customAccount )->atticaContent(); Q_ASSERT( !content.id().isNull() ); - AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( content ); - // For now only allow rating if a resolver is installed! - if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade ) - return false; if ( AtticaManager::instance()->userHasRated( content ) ) return false; + content.setRating( value.toInt() * 20 ); AtticaManager::instance()->uploadRating( content ); From 13920ce25d166716aa0aaf705c342a51c40f7ad7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 11:49:40 +0200 Subject: [PATCH 100/433] * Implement a page history in ViewManager. --- src/libtomahawk/ViewManager.cpp | 146 +++++++++++++-------- src/libtomahawk/ViewManager.h | 9 +- src/sourcetree/items/TemporaryPageItem.cpp | 2 +- 3 files changed, 96 insertions(+), 61 deletions(-) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 8afa38db3..0a738b6e6 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -80,6 +80,7 @@ ViewManager::ViewManager( QObject* parent ) , m_newReleasesWidget( new NewReleasesWidget() ) , m_topLovedWidget( 0 ) , m_recentPlaysWidget( 0 ) + , m_currentPage( 0 ) , m_currentMode( PlaylistModes::Tree ) , m_loaded( false ) { @@ -540,39 +541,6 @@ ViewManager::setAlbumMode() } -void -ViewManager::historyBack() -{ - if ( m_pageHistory.count() < 2 ) - return; - - ViewPage* oldPage = m_pageHistory.takeFirst(); - ViewPage* newPage = m_pageHistory.first(); - - tDebug() << "Deleting page in history:" << oldPage->widget()->metaObject()->className(); - tDebug() << "Showing page after moving backwards in history:" << newPage->widget()->metaObject()->className(); - setPage( newPage, false ); - -// delete oldPage; -} - - -void -ViewManager::removeFromHistory( ViewPage* p ) -{ - if ( currentPage() == p ) - { - historyBack(); - } - else - { - m_pageHistory.removeAll( p ); - delete p; - } - -} - - void ViewManager::setFilter( const QString& filter ) { @@ -588,13 +556,80 @@ ViewManager::setFilter( const QString& filter ) void ViewManager::applyFilter() { - qDebug() << Q_FUNC_INFO; - if ( currentPlaylistInterface() && currentPlaylistInterface()->filter() != m_filter ) currentPlaylistInterface()->setFilter( m_filter ); } +void +ViewManager::historyBack() +{ + if ( !m_pageHistoryBack.count() ) + return; + + ViewPage* page = m_pageHistoryBack.takeLast(); + + if ( m_currentPage ) + { + m_pageHistoryFwd << m_currentPage; + tDebug() << "Moved to forward history:" << m_currentPage->widget()->metaObject()->className(); + } + + tDebug() << "Showing page after moving backwards in history:" << page->widget()->metaObject()->className(); + setPage( page, false ); +} + + +void +ViewManager::historyForward() +{ + if ( !m_pageHistoryFwd.count() ) + return; + + ViewPage* page = m_pageHistoryFwd.takeLast(); + + if ( m_currentPage ) + { + m_pageHistoryBack << m_currentPage; + tDebug() << "Moved to backward history:" << m_currentPage->widget()->metaObject()->className(); + } + + tDebug() << "Showing page after moving forwards in history:" << page->widget()->metaObject()->className(); + setPage( page, false ); +} + + +QList +ViewManager::historyPages() const +{ + return m_pageHistoryBack + m_pageHistoryFwd; +} + + +void +ViewManager::destroyPage( ViewPage* page ) +{ + if ( m_currentPage == page ) + { + m_currentPage = 0; + historyBack(); + return; + } + + QList< Tomahawk::ViewPage* > p = historyPages(); + if ( p.contains( page ) ) + { + m_pageHistoryBack.removeAll( page ); + m_pageHistoryFwd.removeAll( page ); + + emit historyBackAvailable( m_pageHistoryBack.count() ); + emit historyForwardAvailable( m_pageHistoryFwd.count() ); + + delete page; + } +} + + void ViewManager::setPage( ViewPage* page, bool trackHistory ) { @@ -605,23 +640,20 @@ ViewManager::setPage( ViewPage* page, bool trackHistory ) saveCurrentPlaylistSettings(); unlinkPlaylist(); - if ( !m_pageHistory.contains( page ) ) + if ( m_stack->indexOf( page->widget() ) < 0 ) { m_stack->addWidget( page->widget() ); } - else - { - if ( trackHistory ) - m_pageHistory.removeAll( page ); - } - if ( trackHistory ) + if ( m_currentPage && trackHistory ) { - m_pageHistory.insert( 0, page ); + m_pageHistoryBack << m_currentPage; + m_pageHistoryFwd.clear(); } + m_currentPage = page; - emit historyBackAvailable( m_pageHistory.count() > 1 ); - emit historyForwardAvailable( false ); + emit historyBackAvailable( m_pageHistoryBack.count() ); + emit historyForwardAvailable( m_pageHistoryFwd.count() ); qDebug() << "View page shown:" << page->title(); emit viewPageActivated( page ); @@ -809,13 +841,14 @@ ViewManager::loadCurrentPlaylistSettings() void ViewManager::onWidgetDestroyed( QWidget* widget ) { - qDebug() << "Destroyed child:" << widget << widget->metaObject()->className(); + tDebug() << "Destroyed child:" << widget << widget->metaObject()->className(); bool resetWidget = ( m_stack->currentWidget() == widget ); - for ( int i = 0; i < m_pageHistory.count(); i++ ) + QList< Tomahawk::ViewPage* > p = historyPages(); + for ( int i = 0; i < p.count(); i++ ) { - ViewPage* page = m_pageHistory.at( i ); + ViewPage* page = p.at( i ); if ( page->widget() != widget ) continue; @@ -827,11 +860,9 @@ ViewManager::onWidgetDestroyed( QWidget* widget ) { m_dynamicWidgets.remove( dynamicPlaylistForInterface( page->playlistInterface() ) ); } - - if ( page->widget() == widget && !resetWidget ) - { - m_pageHistory.removeAt( i ); - } + + m_pageHistoryBack.removeAll( page ); + m_pageHistoryFwd.removeAll( page ); } m_stack->removeWidget( widget ); @@ -885,7 +916,6 @@ ViewManager::setTomahawkLoaded() } - ViewPage* ViewManager::pageForCollection( const collection_ptr& col ) const { @@ -910,14 +940,14 @@ ViewManager::pageForPlaylist(const playlist_ptr& pl) const ViewPage* ViewManager::pageForInterface( Tomahawk::playlistinterface_ptr interface ) const { - for ( int i = 0; i < m_pageHistory.count(); i++ ) +/* for ( int i = 0; i < m_pageHistory.count(); i++ ) { ViewPage* page = m_pageHistory.at( i ); if ( page->playlistInterface() == interface ) return page; if ( page->playlistInterface() && page->playlistInterface()->hasChildInterface( interface ) ) return page; - } + }*/ return 0; } @@ -936,7 +966,7 @@ ViewManager::currentPlaylistInterface() const Tomahawk::ViewPage* ViewManager::currentPage() const { - return m_pageHistory.isEmpty() ? 0 : m_pageHistory.front(); + return m_currentPage; } @@ -995,7 +1025,7 @@ ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) bool ViewManager::isSuperCollectionVisible() const { - return ( m_pageHistory.count() && + return ( currentPage() != 0 && ( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() || currentPage()->playlistInterface() == m_superAlbumView->playlistInterface() ) ); } diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index 85702642b..98cfb5299 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -158,7 +158,10 @@ public slots: Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source ); void historyBack(); - void removeFromHistory( Tomahawk::ViewPage* p ); + void historyForward(); + + QList< Tomahawk::ViewPage* > historyPages() const; + void destroyPage( Tomahawk::ViewPage* page ); void showQueue() { emit showQueueRequested(); } void hideQueue() { emit hideQueueRequested(); } @@ -224,7 +227,9 @@ private: QHash< Tomahawk::playlist_ptr, QWeakPointer > m_playlistViews; QHash< Tomahawk::source_ptr, QWeakPointer > m_sourceViews; - QList m_pageHistory; + QList m_pageHistoryBack; + QList m_pageHistoryFwd; + Tomahawk::ViewPage* m_currentPage; Tomahawk::collection_ptr m_currentCollection; int m_currentMode; diff --git a/src/sourcetree/items/TemporaryPageItem.cpp b/src/sourcetree/items/TemporaryPageItem.cpp index 765e39509..4ad95a213 100644 --- a/src/sourcetree/items/TemporaryPageItem.cpp +++ b/src/sourcetree/items/TemporaryPageItem.cpp @@ -82,7 +82,7 @@ TemporaryPageItem::IDValue() const void TemporaryPageItem::removeFromList() { - ViewManager::instance()->removeFromHistory( m_page ); + ViewManager::instance()->destroyPage( m_page ); model()->removeSourceItemLink( this ); From f75531da7989c076201e5f7b376693c0c173394d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 13:01:25 +0200 Subject: [PATCH 101/433] * Fixed TWK-853: Confirm with user before actually deleting a playlist. --- src/sourcetree/SourceTreeView.cpp | 34 ++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index 5313bab85..0e57b8d65 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -26,8 +26,9 @@ #include #include #include -#include #include +#include +#include #include "ActionCollection.h" #include "Playlist.h" @@ -211,7 +212,6 @@ SourceTreeView::setupMenus() { m_playlistMenu.addSeparator(); - const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); const playlist_ptr playlist = item->playlist(); foreach ( QAction* action, ActionCollection::instance()->getAction( ActionCollection::LocalPlaylists ) ) @@ -319,13 +319,38 @@ SourceTreeView::loadPlaylist() void SourceTreeView::deletePlaylist( const QModelIndex& idxIn ) { - qDebug() << Q_FUNC_INFO; - QModelIndex idx = idxIn.isValid() ? idxIn : m_contextMenuIndex; if ( !idx.isValid() ) return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( idx, SourcesModel::SourceTreeItemTypeRole ).toInt(); + QString typeDesc; + switch ( type ) + { + case SourcesModel::StaticPlaylist: + typeDesc = tr( "playlist" ); + break; + + case SourcesModel::AutomaticPlaylist: + typeDesc = tr( "automatic playlist" ); + break; + + case SourcesModel::Station: + typeDesc = tr( "station" ); + break; + + default: + Q_ASSERT( false ); + } + + QMessageBox askDelete( QMessageBox::Question, tr( "Delete %1?", "playlist/station/..." ).arg( typeDesc ), + tr( "Would you like to delete the %1 \"%2\"?" ).arg( typeDesc ).arg( idx.data().toString() ), + QMessageBox::Yes | QMessageBox::No, this ); + + int r = askDelete.exec(); + if ( r != QMessageBox::Yes ) + return; + if ( type == SourcesModel::StaticPlaylist ) { PlaylistItem* item = itemFromIndex< PlaylistItem >( idx ); @@ -357,7 +382,6 @@ SourceTreeView::copyPlaylistLink() } else if ( type == SourcesModel::StaticPlaylist ) { - // Disable toma.hk playlist mode until ready // GlobalActionManager::instance()->getShortLink( playlist ); From b2b7fc4a4e4a0872cec0527de3077fd365cbca6f Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Sun, 27 May 2012 09:02:15 -0400 Subject: [PATCH 102/433] Add a bit of 3rd dimension to the dock icon --- data/icons/tomahawk-icon-128x128.png | Bin 69076 -> 69076 bytes data/icons/tomahawk-icon-256x256.png | Bin 266130 -> 266130 bytes data/icons/tomahawk-icon-512x512.png | Bin 1054090 -> 1054090 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/icons/tomahawk-icon-128x128.png b/data/icons/tomahawk-icon-128x128.png index ec05621dc798269ad605e4cbc9fc766fc5c31566..8df40cb4a1a606f4aa890912b2ad938d58f685ac 100644 GIT binary patch literal 69076 zcmeHw2YeO9_W$nQ^xg>&Na#&KIw%N85iE#U5LAkQ^ddzpJVC|odseVu@8}Z*pMW$e zN(7YNTM}AAPYCJB-T(J{cK7Cnw3`Cr@AIF0PIh+MnN#M>nc3OBFZbRi zM>0Orh+ijVjCdEuhmW5y9A((&NyEnvXZ$zBUwUlX2*ho-BmTl;qeo0fd>7(%$4whQ z8u3iT!^V#oIz>_3{Fpv<#IR9_Uyr!oF} zrOzu$C>By9x<#L8R`h77I2g-KH`M0 z8Sy!I7t?*jBSWW+n;Ju=4x2b`;c@5cMm#cN@`wpQ zbsw~B^n{TR_k`i2r;eUDA!hW1;v`(oYEFG%)X-~0Lcg>tVS}3~L0iKV+qpj#w@_cj z_Tb0JQ5|x--TOX;Bd>pSqM`SQBVYa(_@}*&TW!kdkugl}*6*H}Vbdl*#yG|V|G6tZ zN}v*^R8?v!b(DrmQ>CTSPPtL(qV!O1Rqj;oQ3fc3lwry!WxO(3nXb%Go>5*PU5hI!&FSKBvB_zNLPkex}Y>7pcFfYt@bFc6Gm+pq^4M zs@a-N^V7n#8d`m=xz=9ms@$+o9$uh{0=KDRBfEw{zmcG}`?XKh(-9&Vv-F>X!W zZglJAcCXtow@2Ncc6-h31GjJ8mbm@qw$m-aE!oZP?(ZJu-o*U|_ulUJyN`6A?*4-N zT=%cte|G=feYg7w_jC^rj|h(j9_>7Oc?|FvMup8~fAo(=L2 zsvp!XXlT&WLGyxs3ECT!791MfBKXeW@xiYJe;2$lI4Q(4q<%<`kl`V-L%s-EA95_z z7Fs8?Tj;RR=R&^>{XO(Vm`7NHu-;)~!d?ygA#6)na(GC1>+t)+9}k}wzA8LE!WL0K zqIbl&h}R<)N9>8nu2Q2)*D52byj*2Ll^sIb5G*Q z+)`swjrVJ;uW`0!M9nTW$JBhM=IWZKqC=x^iXI*PPV}$Qr(?ony2gx)c`xR-nB-bf zwR+W>R_n7`TWaOhZczK)+RxTrSo?4tpE~X9JW}VKI_v5r*Nv`wN8K59zps0so_D?W z^+wfuw_a?$jQS1g_pkqA{iXGj8bmhe-QdXv-#0ka(7$2lhL1MJ8r$fj zM%x-|joUOH)p%axtxdEhZJUg4@==rR*STNU;kpUeeSY2ErhZMkHhrw=_e~R;MKrs; z*|W`-Hap+EZu5c7-)tV++&IRH<@E5fz3s!=_ig`L z`#(CkceuI3%nmC%WZlsAhN(9!zTv`+O>Z1~<99bEb!^aaM8_{X9_v)Q)6h&CxzW(OPH~)NdMzt`<}_Sw7KP}Th{b)?{!t zM5hsNjYxc?(<5&^k~Ff@$hSwH8r6B!+)-yocN_h|=#(+N#(Xj+W9*${zZt8K>pyPc zc(3t8#{V)QWWv}9zfG(;@$re%TsGT7CNAr`OG_GjsOL6SHoa_3bl0&y0QMuV=4+_N`|xJ=g!a<+E$do;CZ}^S3h-VAeKq&BVXtlacZ+|&_iz0_ zkNjuL>uq2E_zjOYCcLrd&CYLr`&RH-*`XwgHa#so_F)Sg&#(J`0|Gt9}WL#$H!ehUhqkcPhR~b`_s{% z?)&VP&z5{%|MR(Dczp5L7bm~G@5|V)+J80w>uO)W`gPtn6TXT6w%@nE&2Kk<{&!K| zz5c!S{j~2-{rAEDZu_D856c!bUGUk$h=s5IsQftX$J2|3EZVd9w#DmyYX8%M|JD27 zhd+n@{K^t_$rDSGmyTK*zihy=?Z4dm%ev(^F8_H&vlZX0thI99s_<2>ul89zd$s=S zlfR~|nY8BY+L3FItsA`V;QIU5@A~bo-?sdI+wXsD=(%BiY}eRd|LF9`%8fT{{AE-7 zO-nbo-Mr+_Hh=#7SDU|n-qLo_E=JS%=&Yy>d9{@Z2L&M?Q~h6t^(GZTzZ)?g@V$ zz5D3FW5bS}IX>lh?upqa{ZGzKj82@N)G}%1sh+2{oqpi-i8GVVlRA; z{|WzxIPlU-FI`n?+>21MtJ;A|L{`Kaq!L@d!cCpC+m%pFD}-gfu6tnblUEOx}Y=kX4ySjSmlBTF2ouKQ+H8)qu^7TEbYufqjprAyzI&}_Y1qB^F z8xir>_lmOrX;nRU86x4G>hG`Xsi~J`{c~>r5eo3tmtQImJoumzyK|?~p=r}X+`Xjh zH`^4Yv-Zayx7m&yX{;PL;H|~QDax5MigNa>A!Ii!plv7xg@KSEdxLa{KYt|-g;D@& zUY?>uArwzfMF|gA)Sw_GD=JFQt6lrxh2Y@T-gn&bYb#A#8n3FBs~r2H98?BVYN8g1>!_ph$|4MEPL8HPDO4y36-a5& zKuN1x_tb@mh?RMR2Y+45W?N#E#E!0_Q=<+O!d- zVU#y^SCogfB}>NIR<86?Hf*5qbj81yC`{RVad? z0EXH~Q%EbhKJw9u)MRUFMh3J*S9Ms5Tv(>0rcD>0>DckzR`u&IW2gPGkDaQj*=XEo zS17r*{#pFFCVKVtci$-k?!C9bXwTO5vFfHxPijB>P)%L8PK2%p28!7>hnFD`Qs5*& z#3>vRyQvfo1rQ6smJF(yZkmdG1#qdp)C5|#gVxm4R8_%rkmXKwZJ zIgVT}H=8XtHxF}*iHcROg>X$MK+^g1NIj-wI5sLC}+jrlMQa{FiI_L3_ z5O7#VE$lU;rrEaQ6esdcVLHmNtc+GOpQWy3eG&j4LQ^v{6&+L9$rdesTNE1l+}Pp6 zmm|vuijV_EfP;}gy|B*T75;VwI1e)#;_WT;C+WIhsIGsiz5Vvx>Q`SGbGffCjV@#c zp_@$OxRw!$S{%iu(AkDV0UU%Gg15@apubx6*=H>yL#zU(hm(sMHXJ=_@Zg`&Pk)=u zmH~tCw=05!PvqX!3MWpVR;outDEiT(idwU#poOXb%=XSZgJi@92HG*N%1C9V2-s2p z%;7NM`4+%A9~OY+Edevm@ORf|AGGXjRl)wjvBr&$ejOV6@Z(QC1t&%v#&lf&HbwYb z6o4axqnaT{*Pqhn&!4Tn_L`#m`Po$u4^G|Uq*ZFQ(;8q;LC5}rEiooWx##%tt{Yaa z+-=jetUSA&)529*F%;fMwOCmR*AG7YP+F-P8cN|QS-M^`ch|05t$q6kly&Ru6h4JX z;8>?H1sJD7V5C!`mX>nl6QogIO^~#T)<>gP6F-DcIyAe7hh8;4UjNg9eA1 zy!T!&^f(7_9zbhw#ij&t`5_-qS#_q-5$VI!ZUqZ(!wo-_T9)~u|y(uZmU#Cx}CV6<|9ldZN?^ts3MN}bU z3B+gMM1-MXcz94$K!8>?E6cr2)vBTOeSP%~zP{c8e6U1i!5ofa>?p4c73zOc^;JB7 z(1U}umrtL5>&f-&|Lvw}nYng5PjAygSa=bwco5!JyqWwKxTL|-M!`OQq*rWgqB>%P zqSUCNW2cPEJXy>aa_GoHLmez(h@S#VjUkBUQG$K7>I>T)&I~L}Tw0p)^VzfZWhp7C zKOZ`TW7Z0Rqlo4-!|BR6hdr5TjWFV6`vgAa!;~!Rb;jwb`$GtU4>f2Ic1uV|bXQ+r zj|iR*$jA_3Krva5aZ5O*^&d41gNF)?UrxX5duUi5zaJX<;ixaZc+L~NgFnT`(>z*l z;X$-wfgP{3fMuTI4Pw%Dy_x62h1=DcGj+Xsb>nFoMlg`sO>-(F6R|MB?14GL$qWo- zgGgZx%USi2Afw&KM>&z3tG;vWSoWO#`!A(tWu>4Pfy*k677LihQEw>&8At`-(u-a< zg-?cByl_?k9yQ{YCEsBn1OoViNLaM5Z}ikAO=>?79v&V{tAn*Zo;Qk@S7QIo2U8R| z+9{rXDhT+gxx1@BXJjPZ{_C$dVS3HMG2A2xQJFGfrp9QV7cmQ0N4Xd~3-i-NQYv9J%BPug;1<@0^0C5(EH(0rc8K z2)9N>wVqnPe%-EqetxtHPz3gyL)_7S2-8q{{1;_*k$$wV;4!ndHaGV|mlZ2IxvOdh z{43H(OIBeesIUUOF=vi4VaynLs3XGv@WWX3z4z>TXs8fOt`Z5Z`J>)c0OnE4DRTMb2aHO>bUx>$;Gc?%%Y9+jt`sFNkHWPCo{0Df0IxU=BIy)7rvPVjPk~!Pw-_f~ zK>Fo@-5^jAEMGYJVfv$k%%fR56vbCgry$4p?HX;cWBdNRct>COVTx`ga9 z2a60^1u6uUfqnv~2l@z9gm6GrKv=MkPm6c2zy8+#VPOGEdb&(|Wu(9G*#;;O5iiNk zPQGo;nqG*Xg@Vx%RA|X)5r%fk9;{^_9X{`c3lr7np0g`_;A6KNUOcF#*onlM0pbKQ z$v{cPkf8#h%gE%0iHbuX-=06O57@BbB1Sw-J%xM}5N`tGWB{!J=Y7tLbnGZ}wo?&- zqk5@<@}NQxJOQ){K>%8VC_s3mpI@ux9Xk$as%bXeI5x&rifn>`<|64gc~vC;(54-Z zq4vqeiyI$azy48_O#+eR3zeW;^s@8i3dz~oiZ7N%T2 zTrt!DL_OEO{qPwfAszJWY-2@aDS}}!UFRRl=L83jS;va0Lmi>a(rdPXE^;vl;oDF8_-HkjElaj% zXH$z402KOe07pOPdZt^>9ZlXpC6G)i0#^=!@a(E$i?>>vDph)~yYa?RUMVTM9mm!& zO^O`K%0I4=j$+Rwdey3Xfg~=^uml_=93Un4Y62K*$W$qFE zM+VZ4W6a_x(n*Z=_VsNZ*R9(tRW8AWc5?$ujDdwbm-uH{TNKt7XJ#hdxo+J^#1Db* z^qDwCx-?KI1D6AZ&)~Lu_Ypqf!zmXT#YjSb%uEPf?(t6|$fGhaE-GOZQ#Ck{AL4)n zgwM4*M>z%0BU6N}fFl5od^&hg?tgS3`P_Zv=;X3>Z$?_$Z;^`^kKI$XYBJwHC?o&S zgb^TRy-z?u_dA)e=}#RzMn4so@fEkL^um_Q{jVzqW4WyiVYVr_iYcaRAHYyKKr(=bsYD4ho1n ziu4OYw+$HZUGv1mK%Nu8J((pJ`Bw!0m~V308e~cqHp;vgFP@IPKTwZTCzr>i`U5Um z03PO~@Oh*Qr+NmeK0bDN?20r5PUX^N+|kY(6B;{i3~&ymMgSkmGzu3nceDJy#P zn2H=K6*r`~FG2sK#Nd(w@FXt-&hu^JkuDt%C}c!inrdF1^cG~&2Q-~MR)#jf&M6- zN6z-q@I$cDF-8dJKRZn-0g@(VBoQk?c>Z+$M*RLemwa^eI0euG>;S|A=oC^BM5h)m zT7;;gd^cl;T>p>$qs2?jw%h3=oNN8rXQPutLioZ7y+dKEFawz!`{cLST`*R7OSUs2 zH&~TrXWQRz*zgV%uLGb}@CR@UyVy{o0<2xTRtbm4Ka=NkzWsJKPxU&tBob$W*$3VW z@E&n?o>%VgbJ=Hl{+$20+@tVm4dMY5KD~ZN=+m>O#P6Fu+e(wBOYE>!vXZYk7ihUF z7OoEsrD-M&mj^n#oc@whu;bZs_wM_1BO^8L{#pDJB`|qPUenStI2tqg&x0|csP|Hf z77rr3I-m*w`%(Et5ibxNZ4^ko>;~)qPu*I#9;}CjQ32$oOLl|B@Q+=R01YktY#cdi zK!9rd=_juFIr8cB#R8}RoC3&Q&W{o{<3-Wdty_yy4=A1aO+-Lmw!6@K~ zZDVXc+BtH_xT_X&v$Kb*pME+IOinl057frUE3pr%o16Egb?d$l{P<&!3%FU&vrT=RFy4ztH>5Mx4j?L+Jv10%G(aBFXV5ixs%`%G zBMZBIT&wN{aLKm`K(Cdae}R#YdkJtp>w7%))P8m4N(C>GDA_n<@@Y=P}xX>J*16%?W zrND0RnF6qJVU9p^=e6K++LNY5BI^76}~;dp!3moISQaHk!QXF2rQ3F!(N zMUMb*^l`O-IzU%ex|)K=nC3$sF8}reIC_r&tdY<1MFwbws_;-IaFTRt6HLFo_13L@ z5+8YFTdNi=nxLY;x0@TyW^oKHvhDIDVmczd3`NrqV~0G8es1zeS^mSf19)i9A(+e~F%yLNri4*h^|0H>cqgQbuH z#3v*uk4>MBvNFV85mPr^I<<tX zcm+ZshQ&ljD+f1nj|S?3_x8oa8Kcmef0!k4Qz;l{=Zp@bEE?74<68iG&hXYzyQjzC{_>MH^KqT~y^18kG=ID#~{2eyo4EkNg z&(?6H{h8*?yCGH$U|E3zxC`8{4!_k?uU$L7;WJj|e!jPlbc+}f1n&V%H+BKPpxWNM0Sf0pjvS&|&v`(G&KK0N;12Omc zc^I0Gi)leh#pGH65xdc-sR1SevtJHAn9Z3}fZUmNX{ktxkYg4r=|a5`NB5)Z)yJbf z%8J-r!q1XCt1%%esxIo)15gP#{S=rk3n;)>UwXR-L9G!tvrZh%U32Dx(b z1JD{tD4+oAw``F_Ornpd*aZZ`iB0BsQe;qQDmU_|4*W=}a z0K9Sy>XPY4xdK7RB_5=fh#%bNGA!)K5&f$wRlZv=Wy*}KoE%yKI*6_~UIp+LcY}Ty z61a?hB$9rar-dhIK<=&b#Wh$;I`G-?@F;!s=+O(#v}~DVgFwj(4mY+hxWND7@M90x z-YX!0Jm9LSDuAmdS^)_K6rfYfmXc`u`R7rH7`!Ln4IokjjJoold5B03NB{G?c2U?I z{c(VJ09OH}di^Lrip#vXd)kxf;iqdETtBAc3DaR*V* zpd~Xn=r`~)Rl05VoA->CJFqc4hvDGy+SB{G6yO*T z1r&g-^5cxQRja)Ci8ioPOn`-sCQi&83tHyRNE0eQJ98$_e1YQxO2h#Y0jYp8n|{=> zgzw;B3HWIS4Mj2gXva#S&i?&T$2xZW?ajOIeiU{2+c=grut*}BGKFI3&&Q8$qYSzO z(U3=#6YTivSoSUb`+uC?s1Y9)UC#fK@xyBLuTi5GxFm+$6V3zZ_?5WkN4`s;1pH*T)jvlcX${;? zow85J$e6xi@Zb$tdy;UD08R}y2Q9d9H8^-ukp9B>k?$z$YU9O}V>|fd9Ib$Quw%!! zRGg}Evc@tM6r$e=Kc)e_dq@bq|40CR0n0ba_ma=@lr924%W9}El?+pwq~`y#%#W$z zhN7U{F}$>S@WKTOpXUE4fQ}zWf2nJJlqo)t(N5uV{E{W?M}M8lq4NeAIFW46&DA>` zJ=!Sc{`=#*^zYvS#ezND+yYR(fJf|Hy|}oA!=hixm4v^zhRTpGxQs!h&28NHT?LQl z3*ql{V>?Xl)>(j}c>$bK54(hY>(*_ITTTgFC~!)UbtbN`5ysxN!te9SCt8t7EwqS- zNMs&@tuu0%M?sk|7jN&P8TtYz0h|VC37BRzfoM5`$>8a7#b{_XoH;NCgm!DAR%UO@5pP?t!mzV~lu6Yix|I^2$a8 z199aG#XyGl_W9~IN>S+a1!xI)U#?XE>Pc_~zZ5ii!2SuCeRZxc+6-q3k6ZPdckHgVm+eWb+1;Gh6-yMUioi|f_v@S+a_ zonq1|DrZVuG{9-OZl2{e4aSar5Wf^J)(@@R;I2-(82hvgimI81p;OJ-BiUpuU zBgNx)-jgs50Qy#1|M{@Xj^7;6$DKR(=(Zt4j^*L=Fz9Fq=!Q>R{L--y{iWlt82yE7 z+g}I{K9pX&b|xMe(K6@n$&^Mv{D6*;k@e6dm4H^yqksa)4>IuZ19B*5899jaDvDv5 z9Nr^{bm2Sjb1k?fSfigSgK{kcQLjKCjuP>UK00X#%DdWsl_!m$?9Joif>ZChD{kC< z_uU1${ruhCIZxtoXvsn7F9Cnawac9=R`p_|MzQ7-Lup88Hk&Mxe&)eawhj)a6HE(0 zAIMW%@Xa^4D$3XRDHi@3hxsH>o^7Kciky7lnp4)DNXbuQI<_j!Z}o5|kShX?el7zm zMFG$bL-F{FKAYfD|4sTdK3nifOtin9o<1jb!@@7~9|dCxC%=|U{bxO~ zbWm>9W>ax~(cb>Rft!o<7FW8n-ue=-RrfrxXyB;!`%+@1O(JDYPog-!*a zA5dxLA8m=*Dh|KcC!;ScB65*B^iN#qzjJ*lPINf#RV6-N*%lSG?EOiT9?i+i<7f%a z$jUN)r^aBm(C=KoDE!v`h4iVC|J{T)tnjM7LA2?sIZzZwKc>7oIXN8RVE`(CmqP(O zGc#+c=V-wZAZRi4#+_)HMT{r{(&Zj&>s?fud<$Ti|9oMXZIt`MzMyg;{74h+w=9Hp zH4&BC|03#}ibf?+>}hHCN49T&Y~RR{>+wO#x+l+^@e;n6ie{BHl|XoAqLzy@e&_T` zi-X>b$jD@kkBb>xpr3sXzm~$ef#R9 z-*?}pi@SE+Ez3QNezr|qRwx3$l~w6iZ*M`J7ZY<(&&uLx6`Eb5AD!{WGgMr-+VRr% z9pckl1pM|M4`iZcwqvwq5k=-9fSHiHNj9&5M0}YOSrj~{0V)FT%|eJ(Fi1yAz>hwN zgNSnMo8c^$q5q}T=d%T`GiU7G=FDk}mpXa))}Y9wzqI-lB)`b&9{kxmgj|3B<05>1 zYsnS*$rsdZ=;6V`Gu-pY_W}6Bi&OwIoXU?2uRsrbPNqkN@t1We}oA0aa& z?_BMX2ns7*2^Gj;kSU(KD)u8Nd+po4g$Pgo^L| zTW#ZN;^(z!{6-m5XQj)mE!CK4)-S&QWvI`Fg)0s;k|KSR9B7k~QV>7$%=AjX=vAv8 z!(ImaC7~$%Kwgl3$SeeBI8c@rz{7D^Lc>q4>R1X%BOLceFdhIQ&J;1RW`>wPen;1M z@<&gE3P9UbY4blj!^U_m5ishLVA(vj6*pho9rSfsW7dxj;V| z6v(%CAbbEmwQdEPG{nhB;UaixwdW{ehx`u}&-FF;Hs+<19==YV+1Nrr5x^wYwlB#xV*sBCaKDFFEA829WP3ew?WN#{U> z3{GV^NT~#t^XHVsk`)XlKC2Z6ev(XJFs}s=Bdx^#U#0p+2d}_?pARqL(N5vB0Iu?a zawf>JU827*mnR!D`T`BNZ$DkBt%^@f3yMfx*yzqbw6$?ElrO@4!>Z zk<9e;Fb_ToFvfR_d z;I@>ZD7;#LXe9<`VWQar_zg5h_fQTUU?1?`#r|KN`bM7&T$TD?PfZOsw<}?iU8A2J z;Ez5c@SnWz%p2}}T#!$MF_mC6C~={HX2mouEN=z;7!OYyPz4G3%M7bP1+VN&arg}~ zko~Bsi(j#H<&jmu?Rjza<5 zYS)g#2})_0|AbT!%oZ;Xl4dYNiOkI8^G4Zb!j)E_a)~a&>NxPT4;Eb3N#uyYq-^25 z{CdULmmfvapx_Vf-=8}nH#b$jhk~}sg8wqqm2$h{t+%8dH8r)K>qRl^S_TC|r=Kf3@L@EDJypGshUoCdM85fOhW_-?EO5GID+ zxRW7m5hH>?y4>TjR4sm3$avPs^Hkh#tXu_PU(jeF{77RuI?Dg~SL3eq{%L917~VORB$`vXA;w`UI? z4zLxlzD})LhpvSK0-t^QDY_$HBDz^Wc+lVr6I`Jm12*2vi<@uyqje-^XFC8f!KM5BH5#`u7 z!&x*3rwjdOC83F5x?X}GMRHrX@ZA10XDIyrfK7nk02}Jpt9P93T}FSY_))h~!{8x9 zq&@qYGhI~UOrOj2bH8BcsZ(TWVFh5Td9`aFq*nfPuSI{HSY=7{n?uxc~WQFFDamS-C*JpoTTyoSx2uoHYNm z02z)cfCVmugse9A0>tpM=Q6T5x>$gz)|9||2E2sUJvg`~Vw?)71iTh#7x(1~CVq0T zSp3XGH&cE%eE2AD0Teg|PuK>C2b>G=^~I0DAUM$Q zMsSpfA4Qm7DPhz4_0rBZyv(5f`DYcJ(YHP`S}Ofg5!QP7i4z>$6uzA8Dz2Y`a#2-pXpMc}Rpe>n>mM#LBvpuZ&iQmK;uwe8eN zT56~$_p87Eu0U2IkCN~^^ABINRO2sRynse{o=+6O&8cr{J55`Dh~Fzae%z7F2CM*q zNPCiIjs%{X3r53OCRIC^9SFA`scJbmVBqsq50CofR0*(Mq1IQ$rN|RiwBeciF<*)?gehK)cQYHO6 ziQn|A2CrY+vu6U{b5m4&VG^Ay5x;aE`1w-j@A%RdqCCe>rIx9nfCV_Bs;O!9>Yc(5 zR z3@b+&OyY{eFP&r`q>Ba<*h5DjnE_L-;r;fWJ9lOeTE9LKN$~(WeN=$o0b2m{1!x7* z0LErJB9{m7rU3n=;lI3odGE(gnj}?6E6Qkf*)o1rQ{+(^ei17BjI)6MOG&Z(0KVQu z1<2nNGM@?9at00hT=({tQO?TbtTX~1GY*6f?U#GzLje9r?^(V2b-1Mh&@b==6tFh9 zFH>+8Kl?--V1ERRdkg?<@IbM*B2)e8rwc3M<2ll~)T7f!3qav-2gC!&6k33ir!cfl zE68BcUnG9y8>OUZh5qf_xzk};w2d2Q@I#Llt3#gD45C)rqEfGJR zwSs+|U z_$e^X2Sv6~*2Jbwn~H+t>mDt%Z@!7(uY5_{Rv!w}UjRSf@B8NTX<9Yy$DH7n=Zyf2M#OV3mRUTC+;@m%rk&%QXMDu?Kk`T`-R|l*HNr0fXhR3&l0in z2J+FsT@rqdTI)OmM~8j}d-{>T{F3(0o;?)&VZasuN4#b7k05>)K(okwa+g9e^gHmQ z5%P^MFd$~EL|tmQghFZNYQ+8Q*?+5R*5H9Y#8#01CE?fkdiNJ`aio)@{tSRhK*uou z(J*fKpodKMJkzn`yZDy8m>DKmBN0eh$`M2&mX`CHk)glSq)As4;3g5R0Cx#1WCdKs zFa8MjC*bsHbMdoV5sMa`Id$n$0`TtvI6Hm2aeo3pbI6AyLI$p74$ky5ZZ#xvi!Wtv zwP1zcH*8RRA#fb%h_=m}*A?HHcQ}8g;TLJKAK3By<-`fD04R8_f;bJxbXU*|2Gx z4IMg2ef&1 zq$F-=96+x)$8)Zy0_*^ADxl_boi8-vTCPwc{bq|OL*|#OeXCMD_GUQT@R8@*>YO<} z@R4Ub+jIp#+TfrC_kEO?_wJ?nC++lir~vc@WTjKc0`Tk1*wyiRV9=nMI$ln<5JKxX z=c7#nJ>vpKIuj)alb?Q1P*6aPprF=BqZQyj0j&Tklp|pNW8;_Or^#pMxu-w$@ZsDp zD_5SxZ5+UI^wuN(CxDI~H-1R8OO77O6&p&T-%$xXAfwpFiiBu<9fHC0)Ty8F^KQm2 zpwXbn;&T2QS@>_Lo{a7z_*II-$;ov3D0uRSahd;dEqa-T-$KdW8W?!|WQ!K-@vSm3 zdKNJv2vjtMVkv>+ihR7)o?-uA`}X&vSXJC}yBIoEPG0~_BpWZs4;!n;VO!L1>C%gz z?%T)Z9nCuhz79Z>zZGy8U^zVHGx=!1Ih01fRaPcS>!uvnOej9vz-ivT+EY(8#!G_S zoDpDi#qr-lMV@i)pT2J&EgtCkm({!Hb?gg4?gZE>yQ~&tLYrh@Y~` z!EXZnH!hANo^wB^Mmm6L05Si#7A+785??XS9XD#!@>ADef093h%fc9im=R3Ucr`#A zL=<42J{Q41abK|D?EdrT zku8qiCS2+0#R53@(;9HOQ-Da^S6YD58PX|*ej?;}!Nn-=LJzj>+NCsa*pP>9X!`qT z6DRi4@zZX`$P%q`OaUeFpG@O7{$JX@ox-Qk$(IuVYw3%q5sFj*Gf%g>UC~Z{r z=z*l9`S^))EereDBaR$7+4t9951?)wfZMkl05thj0;VScEJqK~D-;}L8ts=vKN*2w z@x{0+;eT`Nz>xM?QI0$owO% z||*1T3^ zd&sY}U>YQ$)@-yy`i-IBBKp7nl7e0*PoC89>)Lwt>YQGTX%IOM+$>cb|FIdCi)r%T zJ9coi)AOhBX#waAb4n->N*swOi4RKHGM;+=`3(meHe9EfD*|bOvNq&xxCTh15||)) z)CYikoNw(-H;wcU2xx|4QGh@|iT=O|FVoYUyPV+RKp zoj>x9ev)M!9nK%pB$TEA*bK~LCHDpi34?RFF2&D$vL>e){F6qkYk}?}Ps*SK91_(N zN3IWc>GBG0TL7p8TpGFoiVMWU4GcOk+{mGm$N7FMfXllp=IEjAVuM9vS?DjeF=QI<;lHi*>2uTiS#2jOig^|Q4}SPChxniX1p@snhC+QoIuC>Ffz!P3&>`}P z1LYtf4#0c*NERuG8lhBWKrvRzQ0C81UD>G7Y<$q(W@(~y#vJk}BRykbfMEvEDGMXs zNmQz&rRjSH4tx$p!e9!x<3R_pB!!?Na?;T%o_D4#@~dd+`3px=o+{ zvbuji9YBMhsOZc;;jths0zZoK`#`f367tSpy2SNArvds)95hshVh4+>3ZP`>=92Ng z_r%3@#r`xD5nLc62%I5!ivkiPOa95NC;`g>_?5=%l9B@V4j#M^KWR$8fJ;RmKxs=w zHt#@z_}>y79Wd!}h5n*C+OtOwj1!eV>-xC+V~@Rq!=H9M!ZnHt>*Sx@JM-^y{1gQF ze;R(kzyA7*P9H}+S4cGfw3e2$jA-HDvI3wgN8QB@YuE1jtVWF&@gz>31VS@qPXKw2 zqsvSqakz@m@K3HpPyMA5G)zbcIy7j|PjCw8Bvu8K<{z;7-yVeFq=&Q_P#XP(`ivhr z(w47SVaNPG$2M%(i|QYL*!g=t2$VIal;ZhEfji+RZ&e(AZM=Flts_?ehXDHk@qi0} zLaP9zIYL#L-XDT-@^tq6}c1N{i2P);WGW z?j{ks$0~X{S%?v%I~>{4#$0+we800HFX*h~?>DA$*mcVD(=F zLK+B{1*Bk@80j({Vl>YB_S=RVyLaED_3Gt=y?$Bq%Sxhz`h{B-M(Ys1a?#IEyK~hl zuKhXsIqJE0LdUPj4Irc!3guxi`^0(WLj1;!`(8;(dXpOwOyrP|z`2pqh5nKWW}e&| zQy7xWDM5;1iHIKrwD;VxmT5SLG>5yKTqn?klmG*epbMLru z;rfmpc7;#*D14L>daQcZ)uhR)&s&zW_(yA_;(dqc)vGh~>}(2~P9KHOx&J7D%VjQ| zT?*w@05*;pNWbK!X&Ixw{POvqGc%L07S%)v%u&y{bH~M0nv@Aq&Rry7ERUb|uwT5W zciz1D&Wpo_CBF6Svk#i89OR~|f4^@~O86g1=_($ub;fdc(TeoH&O-|+#kLI4j=dLN^d=^0K>~g4x0uV_~F2v=jX?eG=UfpS> z-F^Yvk!(|l6m4ZGbX+cAo@qjjG^QKQ4fUUSbaVvBFkg7cwf6jzV>n{>$nUCpoC$Mb~~f?Xx~1fo4A*K*3W14g=^5 z6uI4t^kPFr6@U$AXW8v%u`y$W$a|ho~=V=d3OTY1#UpgYAj&`jZAb`h2VG^VRdiu8-y4=763P(zQRmKYJ?!h-j@~_x4v_x_$c(zi-|8;~Al$+yS$Kg#vcMQ@(Iw zWt8WdoSr@;;P%@;;oe1g`!9G&qbu~2PB@En_&Db~nSBa>Ghi3s7@$l}AIcX9`AjO1 zT<#kx0e`om3Pc$GubXe4^sKLMe;w})(B31R=3bOR?oikvSVO>u zYJvJ3Da>afd;n9!nRveSY_C>LQDGr6!org6b?O}9FEM4{$9U`!5pmvufoa~Mp){Kk zP}d{-!UcaNEv<(8nKRMoYfb(9`MS2axDX9r=;BwpRJ?kI%^P;SAbv?O@t3FnsK0UJ z$Iw;dEP#U+Q*rr>{{o!9&}GXmV%bN}KMr8c|JD>xAuE9PBp95w?kevpQv;gAKvHV> z1O>I+)3)tf(YOKQAy?D18~8-rOoQYNE#a!d5HeFm*r-JdVZ9j2I+Dk1VW3r?cQ_zH zC6c;$jE!9xp_6YG@oQQP^5Uh$c!T}`bZ&72bSRUQ#i|5LR3i`g**`QyMJ*n`G+y@p z8(cxRu+RS!`rK#LD(>vj(c_xm68-_ic}}8IgpYO%-ZF9p0-4TDoe)4Ypz5M7UEb;A z=NHNSa8tnCT@qoL;xrV%bnL)ru?`|gqp!wvVhEVY6mseHAub4*{c*iM6$pWqDvTd( zP;rXIPZXT{Vg85g+Lim+{{7tSao+8t0#FgS8Ys8(hq{G=F&qjdS6TwSbqqlz9f<5- z$H%XQ3VYm9ty*I@m~B(qFnl6QP8Gs%aGs+~5;>AZ2uQ<~|7FjBX=b=G^~EHKc3o-w z@|ogO_{2@j%9WR56BFs-9|i0LaPHp%;I=P?&+XoFdH$$ZWN_kRk@=O8NF3a`@k4}; zVl?8-e(BzQYEMtka99I;*99|%VZyEcQ23$*Ob|^l6@Zq50~5hWW7 zvwR%+H2HM!xTnD@mwPQ03AS%`fLDws4E(zmsb=+@r}~~r8VHWz$$>6fJkV@jq}>I z>o+(eB0%914%@+a3t4u^AXEyS_8w7OP{9$G9K(rpF2j7fk4DX_Tc75RuWs}0-5G}u zXTP#@C(r8<=+IHvH2H)$0GD^n<6KYSUzPB8Du6{Gt${ay(?SG56am+UGp@Vt)=4#M z)(z!of-*p`^b=$>%LqpyDglY$l@~M48b&Y_!zw4mXbrAZeQx5QgDSt+aS%tho;q+K z>-!@|INCYtDR`Q9j(S2ofL4I{JjqMJ+W}WCIQVqcFcyu7gT6?1Il(7@B|8w!9p=Y2MB37ByPQ3~c$PvAqyaW*QFk)5Akp85t} zg>UunD_tD%{8kS?*J6ILBL!$Ec#iM{Ksv2>?BN zS_78J0#NWyUB}&34A+_hSfpEuz^Q>gLMVXK1C@aO0`zD;0rLgC~Gi zAppRAgm3^Ag31tN-iNgf53k!kJlyjJfB)$Ec!*OoJKHUkFJDk_+~_=vl>P^KD+G zN^m4TD+_JX{CJiTBb%zgv3-uK4aAS9q$t}H6VuMBYEHV{o(t!bW*T#im}|xG7>xUwSLU-Efpw@z z+?gb>Jv5!0=vLc^UVGu6r~uAfv@8P^ zg2JQ&NdfapVbc;g3*Hhw^PLp{w+=y30Vq660XXU{D`1Ui>&kSioF(v5h2CMy2enae pPVeqr@4?j()LF{Rzg=6#r2p_-pC|77h`s9Fqfhq*HxGIC{{fmV?1KOR literal 69076 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 diff --git a/data/icons/tomahawk-icon-256x256.png b/data/icons/tomahawk-icon-256x256.png index 00c4613fa41dfd6e547b9be64a28d5d36032fe43..e0793782d9bdab853821bc4a0c4fe4c47737c3a5 100644 GIT binary patch literal 266130 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 literal 266130 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

    tHH82n;0eA% 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%0D1t7DIq4NpjSCl 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 diff --git a/data/icons/tomahawk-icon-512x512.png b/data/icons/tomahawk-icon-512x512.png index b53561c6acdf8aec86df7cb9ef0d089c5b519ca5..6c9757a3d432dc77ed9fd9f944bccdb54e729e38 100644 GIT binary patch literal 1054090 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ⅇ{< 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

    `hph~FrvN%A72aitod$(VWuTlSZZf+G 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

    K>i4Y-)+ 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

    =td)`xXs^hb`P5S3nd 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 Y@ju@ELx$kze)gaI%;$dUU;exQ51zyi8UO$Q literal 1054090 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

    PwJv1JGt#_u4<^2&e#(CueMG1S_YMj^T4oTti## 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 Dz>kdg From 33cae66d950aa6098d5685c8540417fe1e580b8b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 17:33:38 +0200 Subject: [PATCH 103/433] * Renamed infoLoaded() to coverLoaded(). --- src/libtomahawk/Album.cpp | 10 +++++----- src/libtomahawk/Album.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/Album.cpp b/src/libtomahawk/Album.cpp index 4dcad4ac3..ca05f53d8 100644 --- a/src/libtomahawk/Album.cpp +++ b/src/libtomahawk/Album.cpp @@ -82,8 +82,8 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& , m_id( id ) , m_name( name ) , m_artist( artist ) - , m_infoLoaded( false ) - , m_infoLoading( false ) + , m_coverLoaded( false ) + , m_coverLoading( false ) #ifndef ENABLE_HEADLESS , m_cover( 0 ) #endif @@ -110,7 +110,7 @@ Album::artist() const QPixmap Album::cover( const QSize& size, bool forceLoad ) const { - if ( !m_infoLoaded && !m_infoLoading ) + if ( !m_coverLoaded && !m_coverLoading ) { if ( !forceLoad ) return QPixmap(); @@ -137,7 +137,7 @@ Album::cover( const QSize& size, bool forceLoad ) const Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - m_infoLoading = true; + m_coverLoading = true; } if ( !m_cover && !m_coverBuffer.isEmpty() ) @@ -202,7 +202,7 @@ Album::infoSystemFinished( const QString& target ) disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), this, SLOT( infoSystemFinished( QString ) ) ); - m_infoLoaded = true; + m_coverLoaded = true; emit updated(); } diff --git a/src/libtomahawk/Album.h b/src/libtomahawk/Album.h index a0fa52dd9..eae36af96 100644 --- a/src/libtomahawk/Album.h +++ b/src/libtomahawk/Album.h @@ -56,7 +56,7 @@ public: #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; #endif - bool infoLoaded() const { return m_infoLoaded; } + bool coverLoaded() const { return m_coverLoaded; } QList tracks( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ); Tomahawk::playlistinterface_ptr playlistInterface( ModelMode mode, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ); @@ -85,8 +85,8 @@ private: artist_ptr m_artist; QByteArray m_coverBuffer; - bool m_infoLoaded; - mutable bool m_infoLoading; + bool m_coverLoaded; + mutable bool m_coverLoading; mutable QString m_uuid; #ifndef ENABLE_HEADLESS From 9d064f7689083f91882bf213bd81bf4f85500dd9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 17:33:46 +0200 Subject: [PATCH 104/433] * Renamed infoLoaded() to coverLoaded(). --- src/libtomahawk/Artist.cpp | 10 +++++----- src/libtomahawk/Artist.h | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/libtomahawk/Artist.cpp b/src/libtomahawk/Artist.cpp index c70aeb593..c36e64ea2 100644 --- a/src/libtomahawk/Artist.cpp +++ b/src/libtomahawk/Artist.cpp @@ -82,8 +82,8 @@ Artist::Artist( unsigned int id, const QString& name ) : QObject() , m_id( id ) , m_name( name ) - , m_infoLoaded( false ) - , m_infoLoading( false ) + , m_coverLoaded( false ) + , m_coverLoading( false ) , m_simArtistsLoaded( false ) , m_infoJobs( 0 ) #ifndef ENABLE_HEADLESS @@ -295,7 +295,7 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari if ( ba.length() ) { m_coverBuffer = ba; - m_infoLoaded = true; + m_coverLoaded = true; emit coverChanged(); } } @@ -348,7 +348,7 @@ Artist::infoSystemFinished( QString target ) QPixmap Artist::cover( const QSize& size, bool forceLoad ) const { - if ( !m_infoLoaded && !m_infoLoading ) + if ( !m_coverLoaded && !m_coverLoading ) { if ( !forceLoad ) return QPixmap(); @@ -374,7 +374,7 @@ Artist::cover( const QSize& size, bool forceLoad ) const m_infoJobs++; Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - m_infoLoading = true; + m_coverLoading = true; } if ( !m_cover && !m_coverBuffer.isEmpty() ) diff --git a/src/libtomahawk/Artist.h b/src/libtomahawk/Artist.h index a19f5931b..cf267df1e 100644 --- a/src/libtomahawk/Artist.h +++ b/src/libtomahawk/Artist.h @@ -49,8 +49,6 @@ public: QString name() const { return m_name; } QString sortname() const { return m_sortname; } - bool infoLoaded() const { return m_infoLoaded; } - QList albums( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ) const; QList similarArtists() const; @@ -65,6 +63,7 @@ public: #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; #endif + bool coverLoaded() const { return m_coverLoaded; } Tomahawk::playlistinterface_ptr playlistInterface(); @@ -94,8 +93,8 @@ private: QString m_name; QString m_sortname; - bool m_infoLoaded; - mutable bool m_infoLoading; + bool m_coverLoaded; + mutable bool m_coverLoading; QHash m_albumsLoaded; bool m_simArtistsLoaded; From c5f6c25e933eaafbfe655acab4efd7d6c0ccd1a3 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 17:34:03 +0200 Subject: [PATCH 105/433] * Added coverLoaded() method to Query. --- src/libtomahawk/Query.cpp | 15 ++++++++++++++- src/libtomahawk/Query.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index 94cd4a140..246664450 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -780,7 +780,7 @@ Query::cover( const QSize& size, bool forceLoad ) const } m_albumPtr->cover( size, forceLoad ); - if ( m_albumPtr->infoLoaded() ) + if ( m_albumPtr->coverLoaded() ) { if ( !m_albumPtr->cover( size ).isNull() ) return m_albumPtr->cover( size ); @@ -793,6 +793,19 @@ Query::cover( const QSize& size, bool forceLoad ) const #endif +bool +Query::coverLoaded() const +{ + if ( m_albumPtr.isNull() ) + return false; + + if ( m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() ) + return true; + + return m_artistPtr->coverLoaded(); +} + + QList Query::similarTracks() const { diff --git a/src/libtomahawk/Query.h b/src/libtomahawk/Query.h index 78ff182f8..20e9956d7 100644 --- a/src/libtomahawk/Query.h +++ b/src/libtomahawk/Query.h @@ -145,6 +145,7 @@ public: #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; #endif + bool coverLoaded() const; void setResolveFinished( bool resolved ) { m_resolveFinished = resolved; } void setPlayedBy( const Tomahawk::source_ptr& source, unsigned int playtime ); From f24d11b41a93ec9d63284a201bba645b4fe035b7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 17:34:22 +0200 Subject: [PATCH 106/433] * Use new coverLoaded() methods. --- src/libtomahawk/playlist/TreeModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/TreeModel.cpp b/src/libtomahawk/playlist/TreeModel.cpp index c61cffc83..6194c8e90 100644 --- a/src/libtomahawk/playlist/TreeModel.cpp +++ b/src/libtomahawk/playlist/TreeModel.cpp @@ -100,9 +100,9 @@ TreeModel::getCover( const QModelIndex& index ) { PlayableItem* item = itemFromIndex( index ); - if ( !item->artist().isNull() && !item->artist()->infoLoaded() ) + if ( !item->artist().isNull() && !item->artist()->coverLoaded() ) item->artist()->cover( QSize( 0, 0 ) ); - else if ( !item->album().isNull() && !item->album()->infoLoaded() ) + else if ( !item->album().isNull() && !item->album()->coverLoaded() ) item->album()->cover( QSize( 0, 0 ) ); } From b811b12e774a280cae1dfe3516f7870c5a8a5e86 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 17:35:36 +0200 Subject: [PATCH 107/433] * Fixed AudioEngine's now playing data pusher to wait for covers being available. --- src/libtomahawk/audio/AudioEngine.cpp | 60 +++++++++++++-------------- src/libtomahawk/audio/AudioEngine.h | 3 +- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index d7e777a76..16d02dacc 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -345,12 +345,14 @@ void AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ) { #ifndef ENABLE_HEADLESS - if ( m_currentTrack->album().isNull() || m_currentTrack->album()->infoLoaded() ) + if ( m_currentTrack->toQuery()->coverLoaded() ) + { onNowPlayingInfoReady( type ); + } else { - NewClosure( m_currentTrack->album().data(), SIGNAL( updated() ), const_cast< AudioEngine* >( this ), SLOT( onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType ) ), type ); - m_currentTrack->album()->cover( QSize( 0, 0 ), true ); + NewClosure( m_currentTrack->toQuery().data(), SIGNAL( coverChanged() ), const_cast< AudioEngine* >( this ), SLOT( sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ) ), type ); + m_currentTrack->toQuery()->cover( QSize( 0, 0 ), true ); } #endif } @@ -359,7 +361,6 @@ AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType ty void AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << type; if ( m_currentTrack.isNull() || m_currentTrack->track().isNull() || m_currentTrack->artist().isNull() ) @@ -367,36 +368,35 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) QVariantMap playInfo; - if ( !m_currentTrack->album().isNull() ) - { #ifndef ENABLE_HEADLESS - QImage cover; - cover = m_currentTrack->album()->cover( QSize( 0, 0 ) ).toImage(); - if ( !cover.isNull() ) - { - playInfo["cover"] = cover; + QImage cover; + cover = m_currentTrack->toQuery()->cover( QSize( 0, 0 ) ).toImage(); + if ( !cover.isNull() ) + { + playInfo["cover"] = cover; - QTemporaryFile* coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) ); - if ( !coverTempFile->open() ) - tDebug() << Q_FUNC_INFO << "WARNING: could not write temporary file for cover art!"; - else - { - // Finally, save the image to the new temp file - coverTempFile->setAutoRemove( false ); - if ( cover.save( coverTempFile, "PNG" ) ) - { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *coverTempFile ).absoluteFilePath(); - playInfo["coveruri"] = QFileInfo( *coverTempFile ).absoluteFilePath(); - } - else - tDebug() << Q_FUNC_INFO << "failed to save cover image!"; - } - delete coverTempFile; + QTemporaryFile* coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) ); + if ( !coverTempFile->open() ) + { + tDebug() << Q_FUNC_INFO << "WARNING: could not write temporary file for cover art!"; } else - tDebug() << Q_FUNC_INFO << "Cover from album is null!"; -#endif + { + // Finally, save the image to the new temp file + coverTempFile->setAutoRemove( false ); + if ( cover.save( coverTempFile, "PNG" ) ) + { + tDebug() << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *coverTempFile ).absoluteFilePath(); + playInfo["coveruri"] = QFileInfo( *coverTempFile ).absoluteFilePath(); + } + else + tDebug() << Q_FUNC_INFO << "failed to save cover image!"; + } + delete coverTempFile; } + else + tDebug() << Q_FUNC_INFO << "Cover from query is null!"; +#endif Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["title"] = m_currentTrack->track(); @@ -410,7 +410,7 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) Tomahawk::InfoSystem::InfoPushData pushData ( s_aeInfoIdentifier, type, playInfo, Tomahawk::InfoSystem::PushShortUrlFlag ); - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "pushing data with type " << type; + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "pushing data with type" << type; Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); } diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index 79848a736..d8a56aed8 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -136,6 +136,7 @@ private slots: void onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ); void onPlaylistNextTrackReady(); + void sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ); void sendWaitingNotification() const; void queueStateSafety(); @@ -149,8 +150,6 @@ private: bool isHttpResult( const QString& ) const; bool isLocalResult( const QString& ) const; - void sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ); - QSharedPointer m_input; Tomahawk::query_ptr m_stopAfterTrack; From 418f12743faad5c6ea087017c442f0e6c87bfd2e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 17:35:53 +0200 Subject: [PATCH 108/433] * Style fix. --- src/sourcetree/items/PlaylistItems.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sourcetree/items/PlaylistItems.cpp b/src/sourcetree/items/PlaylistItems.cpp index d0bebc7a4..24780ce16 100644 --- a/src/sourcetree/items/PlaylistItems.cpp +++ b/src/sourcetree/items/PlaylistItems.cpp @@ -255,7 +255,6 @@ PlaylistItem::onUpdated() if ( !newOverlay && !m_overlaidIcon.isNull() ) m_overlaidIcon = QIcon(); - emit updated(); } From d67f4827a8ce480866db2851b66c244f1ba7089f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 18:10:27 +0200 Subject: [PATCH 109/433] * Re-enabled WidgetDragFilter for main-window's toolbar. --- src/TomahawkWindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 10996b4a1..7a288ac9f 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -40,6 +40,7 @@ #include "network/Servent.h" #include "utils/TomahawkUtilsGui.h" #include "utils/ProxyStyle.h" +#include "utils/WidgetDragFilter.h" #include "widgets/AnimatedSplitter.h" #include "widgets/NewPlaylistWidget.h" #include "widgets/SearchWidget.h" @@ -213,6 +214,10 @@ TomahawkWindow::setupToolBar() toolbar->setIconSize( QSize( 22, 22 ) ); toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly ); +#ifdef Q_OS_MAC + toolbar->installEventFilter( new WidgetDragFilter( toolbar ) ); +#endif + m_backAction = toolbar->addAction( QIcon( RESPATH "images/back.png" ), tr( "Back" ), ViewManager::instance(), SLOT( historyBack() ) ); m_backAction->setToolTip( tr( "Go back one page" ) ); m_forwardAction = toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) ); From 8d57ec328394e84a26221d7fa7d29487c63fbe4d Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 27 May 2012 12:22:13 -0400 Subject: [PATCH 110/433] Remove stale files --- src/PipelineStatusView.cpp | 117 ------------------------------------- src/PipelineStatusView.h | 51 ---------------- 2 files changed, 168 deletions(-) delete mode 100644 src/PipelineStatusView.cpp delete mode 100644 src/PipelineStatusView.h diff --git a/src/PipelineStatusView.cpp b/src/PipelineStatusView.cpp deleted file mode 100644 index e87614d70..000000000 --- a/src/PipelineStatusView.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2011, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "JobStatusView.h" - -#include -#include - -#include "libtomahawk/Pipeline.h" - -#include "utils/Logger.h" - -using namespace Tomahawk; - - -JobStatusView::JobStatusView( AnimatedSplitter* parent ) - : AnimatedWidget( parent ) - , m_parent( parent ) -{ - setHiddenSize( QSize( 0, 0 ) ); - setLayout( new QVBoxLayout() ); - m_tree = new QTreeWidget( this ); - - layout()->setMargin( 0 ); - layout()->addWidget( m_tree ); - - QStringList headers; - headers << tr( "Searching For" ) << tr( "Pending" ); - m_tree->setHeaderLabels( headers ); - - m_tree->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); - m_tree->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); - m_tree->setColumnCount( 2 ); - m_tree->setColumnWidth( 0, 200 ); - m_tree->setColumnWidth( 1, 50 ); - - m_tree->header()->setStretchLastSection( true ); - m_tree->setRootIsDecorated( false ); - - m_tree->setFrameShape( QFrame::NoFrame ); - m_tree->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - new QTreeWidgetItem( m_tree ); - - connect( Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), SLOT( onPipelineUpdate( Tomahawk::query_ptr ) ) ); - connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onPipelineUpdate() ) ); - -#ifndef Q_WS_WIN - QFont f = font(); - f.setPointSize( f.pointSize() - 1 ); - setFont( f ); -#endif - -#ifdef Q_WS_MAC - f.setPointSize( f.pointSize() - 2 ); - setFont( f ); -#endif - - onPipelineUpdate(); -} - - -void -JobStatusView::onPipelineUpdate( const query_ptr& query ) -{ - QTreeWidgetItem* ti = m_tree->invisibleRootItem()->child( 0 ); - - if ( Pipeline::instance()->activeQueryCount() && !query.isNull() ) - { - ti->setText( 0, QString( "%1 - %2" ).arg( query->artist() ).arg( query->track() ) ); - ti->setText( 1, QString( "%1" ).arg( Pipeline::instance()->activeQueryCount() + Pipeline::instance()->pendingQueryCount() ) ); - - if ( isHidden() ) - emit showWidget(); - } - else - { - ti->setText( 0, tr( "Idle" ) ); - ti->setText( 1, QString( "None" ) ); - - if ( !isHidden() ) - emit hideWidget(); - } -} - - -QSize -JobStatusView::sizeHint() const -{ - unsigned int y = 0; - y += m_tree->header()->height(); - y += m_tree->contentsMargins().top() + m_tree->contentsMargins().bottom(); - - if ( m_tree->invisibleRootItem()->childCount() ) - { - unsigned int rowheight = m_tree->sizeHintForRow( 0 ); - y += rowheight * m_tree->invisibleRootItem()->childCount() + 2; - } - - return QSize( 0, y ); -} diff --git a/src/PipelineStatusView.h b/src/PipelineStatusView.h deleted file mode 100644 index 857357082..000000000 --- a/src/PipelineStatusView.h +++ /dev/null @@ -1,51 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2011, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef JOBSTATUSVIEW_H -#define JOBSTATUSVIEW_H - -#include - -#include "Typedefs.h" -#include "widgets/AnimatedSplitter.h" -#include "Query.h" - -class StreamConnection; - -class JobStatusView : public AnimatedWidget -{ -Q_OBJECT - -public: - explicit JobStatusView( AnimatedSplitter* parent ); - virtual ~JobStatusView() - { - } - - QSize sizeHint() const; - -private slots: - void onPipelineUpdate( const Tomahawk::query_ptr& query = Tomahawk::query_ptr() ); - -private: - QTreeView* m_tree; - AnimatedSplitter* m_parent; -}; - -#endif // JOBSTATUSVIEW_H From 8830593f1d232b103083d86598c2b9085fc6d262 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 18:23:48 +0200 Subject: [PATCH 111/433] * Added volume / setVolume methods to TomahawkSettings. --- src/libtomahawk/TomahawkSettings.cpp | 15 ++++++++++++++- src/libtomahawk/TomahawkSettings.h | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index 8489c52f3..01a794749 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -158,7 +158,6 @@ TomahawkSettings::doInitialSetup() // by default we add a local network resolver addAccount( "sipzeroconf_autocreated" ); - createLastFmAccount(); createSpotifyAccount(); } @@ -712,6 +711,20 @@ TomahawkSettings::setCrashReporterEnabled( bool enable ) } +unsigned int +TomahawkSettings::volume() const +{ + return value( "audio/volume", 75 ).toUInt(); +} + + +void +TomahawkSettings::setVolume( unsigned int volume ) +{ + setValue( "audio/volume", volume ); +} + + QString TomahawkSettings::proxyHost() const { diff --git a/src/libtomahawk/TomahawkSettings.h b/src/libtomahawk/TomahawkSettings.h index 3951e9ec3..42fdac340 100644 --- a/src/libtomahawk/TomahawkSettings.h +++ b/src/libtomahawk/TomahawkSettings.h @@ -47,11 +47,13 @@ public: /// General settings virtual QString storageCacheLocation() const; + virtual QStringList scannerPaths() const; /// QDesktopServices::MusicLocation in TomahawkSettingsGui void setScannerPaths( const QStringList& paths ); bool hasScannerPaths() const; uint scannerTime() const; void setScannerTime( uint time ); + uint infoSystemCacheVersion() const; void setInfoSystemCacheVersion( uint version ); @@ -81,6 +83,10 @@ public: bool enableEchonestCatalogs() const; void setEnableEchonestCatalogs( bool enable ); + /// Audio stuff + unsigned int volume() const; + void setVolume( unsigned int volume ); + /// Playlist stuff QByteArray playlistColumnSizes( const QString& playlistid ) const; void setPlaylistColumnSizes( const QString& playlistid, const QByteArray& state ); From 5e0d8d22923e9450d1dcb89470fa4e877577b353 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 18:24:16 +0200 Subject: [PATCH 112/433] * Fixed TWK-812: Persistent volume settings across sessions. --- src/libtomahawk/audio/AudioEngine.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 16d02dacc..8fd3e798a 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -86,19 +86,16 @@ AudioEngine::AudioEngine() onVolumeChanged( m_audioOutput->volume() ); -#ifndef Q_WS_X11 - // On mac & win, phonon volume is independent from system volume, so the onVolumeChanged call above just sets our volume to 100%. - // Since it's indendent, we'll set it to 75% since that's nicer. - setVolume( 75 ); -#endif + setVolume( TomahawkSettings::instance()->volume() ); } AudioEngine::~AudioEngine() { tDebug() << Q_FUNC_INFO; + m_mediaObject->stop(); -// stop(); + TomahawkSettings::instance()->setVolume( volume() ); delete m_audioOutput; delete m_mediaObject; From 4d281b645c148d46fec22f5b35e262824cb41ad7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 18:24:37 +0200 Subject: [PATCH 113/433] * Extra debug output for, well, debugging help. --- src/libtomahawk/database/DatabaseImpl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 00002284a..f45f813af 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -96,6 +96,8 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) DatabaseImpl::~DatabaseImpl() { delete m_fuzzyIndex; + + tDebug() << "Shutting down database."; /* #ifdef TOMAHAWK_QUERY_ANALYZE From 74af29054af1df20370349622b0fd4de352c6e40 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 18:35:58 +0200 Subject: [PATCH 114/433] * Fixed TWK-719: Handle Twitter names in --demo mode. --- src/libtomahawk/Source.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index 232237054..42733a370 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -194,7 +194,10 @@ Source::setFriendlyName( const QString& fname ) m_friendlyname = fname; if ( m_scrubFriendlyName ) - m_friendlyname = m_friendlyname.split( "@" ).first(); + { + if ( m_friendlyname.indexOf( "@" ) > 0 ) + m_friendlyname = m_friendlyname.split( "@" ).first(); + } } From d8c5dcc6ba8e7f62559887b1a62b5324a439c4fd Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:04:56 +0200 Subject: [PATCH 115/433] * Cleaned up names in TrackInfoWidget. --- .../widgets/infowidgets/TrackInfoWidget.cpp | 19 ++++++++++--------- .../widgets/infowidgets/TrackInfoWidget.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index eaedf96fa..15a696185 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -84,8 +84,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->lyricsView->setPalette( p ); // ui->similarTracksLabel->setPalette( p ); - m_albumsModel = new AlbumModel( ui->similarTracksView ); - ui->similarTracksView->setAlbumModel( m_albumsModel ); + m_relatedTracksModel = new AlbumModel( ui->similarTracksView ); + ui->similarTracksView->setAlbumModel( m_relatedTracksModel ); ui->similarTracksView->proxyModel()->sort( -1 ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); @@ -129,6 +129,8 @@ TrackInfoWidget::load( const query_ptr& query ) if ( !m_query.isNull() ) { + disconnect( m_query.data(), SIGNAL( lyricsLoaded() ), this, SLOT( onLyricsLoaded() ) ); + disconnect( m_query.data(), SIGNAL( similarTracksLoaded() ), this, SLOT( onSimilarTracksLoaded() ) ); disconnect( m_query.data(), SIGNAL( statsLoaded() ), this, SLOT( onStatsLoaded() ) ); disconnect( m_query.data(), SIGNAL( updated() ), this, SLOT( onCoverUpdated() ) ); disconnect( m_artist.data(), SIGNAL( statsLoaded() ), this, SLOT( onStatsLoaded() ) ); @@ -144,6 +146,7 @@ TrackInfoWidget::load( const query_ptr& query ) m_artist->loadStats(); m_query->loadStats(); + m_query->lyrics(); onCoverUpdated(); ui->trackLabel->setText( query->track() ); @@ -151,10 +154,8 @@ TrackInfoWidget::load( const query_ptr& query ) ui->albumLabel->setText( query->album() ); ui->fromLabel->setVisible( !query->album().isEmpty() ); - m_query->lyrics(); - m_query->similarTracks(); - m_albumsModel->addArtists( m_artist->similarArtists() ); - m_albumsModel->clear(); + m_relatedTracksModel->clear(); + onSimilarTracksLoaded(); } @@ -200,16 +201,16 @@ TrackInfoWidget::onStatsLoaded() void TrackInfoWidget::onSimilarArtistsLoaded() { -// Artist* artist = qobject_cast( sender() ); +/* Artist* artist = qobject_cast( sender() ); -// m_albumsModel->addArtists( artist->similarArtists() ); + m_relatedArtistsModel->addArtists( artist->similarArtists() );*/ } void TrackInfoWidget::onSimilarTracksLoaded() { - m_albumsModel->addQueries( m_query->similarTracks() ); + m_relatedTracksModel->addQueries( m_query->similarTracks() ); } diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h index 849e36043..691ea43b7 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h @@ -88,7 +88,7 @@ private: Tomahawk::query_ptr m_query; Tomahawk::artist_ptr m_artist; - AlbumModel* m_albumsModel; + AlbumModel* m_relatedTracksModel; QString m_title; QPixmap m_pixmap; QString m_infoId; From 70fa4b73d48b5d16d6b2202f18793d952dc2fe70 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:05:23 +0200 Subject: [PATCH 116/433] * Use the new Artist API in ArtistInfoWidget. --- .../widgets/infowidgets/ArtistInfoWidget.cpp | 76 ++++++++----------- .../widgets/infowidgets/ArtistInfoWidget.h | 2 + 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 858e90f3a..d2c9c068c 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -147,15 +147,29 @@ void ArtistInfoWidget::load( const artist_ptr& artist ) { if ( !m_artist.isNull() ) + { disconnect( m_artist.data(), SIGNAL( updated() ), this, SLOT( onArtistImageUpdated() ) ); + disconnect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), this, SLOT( onSimilarArtistsLoaded() ) ); + disconnect( m_artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), + this, SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); + disconnect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + this, SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); + } m_artist = artist; m_title = artist->name(); - connect( artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), - SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); + connect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), SLOT( onSimilarArtistsLoaded() ) ); + connect( m_artist.data(), SIGNAL( updated() ), SLOT( onArtistImageUpdated() ) ); + connect( m_artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), + SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); + connect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); onAlbumsFound( artist->albums( Mixed ), Mixed ); + onTracksFound( m_artist->tracks(), Mixed ); + onSimilarArtistsLoaded(); + onArtistImageUpdated(); Tomahawk::InfoSystem::InfoStringHash artistInfo; artistInfo["artist"] = artist->name(); @@ -169,17 +183,6 @@ ArtistInfoWidget::load( const artist_ptr& artist ) Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSimilars; - requestData.requestId = TomahawkUtils::infosystemRequestId(); - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSongs; - requestData.requestId = TomahawkUtils::infosystemRequestId(); - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - connect( m_artist.data(), SIGNAL( updated() ), SLOT( onArtistImageUpdated() ) ); - onArtistImageUpdated(); } @@ -192,6 +195,22 @@ ArtistInfoWidget::onAlbumsFound( const QList& albums, Model } +void +ArtistInfoWidget::onTracksFound( const QList& queries, ModelMode mode ) +{ + Q_UNUSED( mode ); + + m_topHitsModel->append( queries ); +} + + +void +ArtistInfoWidget::onSimilarArtistsLoaded() +{ + m_relatedModel->addArtists( m_artist->similarArtists() ); +} + + void ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) { @@ -227,37 +246,6 @@ ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestD break; } - case InfoSystem::InfoArtistSongs: - { - const QStringList tracks = returnedData["tracks"].toStringList(); - - QList< query_ptr > queries; - int i = 0; - foreach ( const QString& track, tracks ) - { - queries << Query::get( m_artist->name(), track, QString(), QString(), false ); - - if ( ++i == 15 ) - break; - } - - Pipeline::instance()->resolve( queries ); - m_topHitsModel->append( queries ); - break; - } - - case InfoSystem::InfoArtistSimilars: - { - const QStringList artists = returnedData["artists"].toStringList(); - QList al; - foreach ( const QString& artist, artists ) - { - al << Artist::get( artist ); - } - m_relatedModel->addArtists( al ); - break; - } - default: return; } diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index adebbb21c..097cbca8b 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -95,6 +95,8 @@ private slots: void onArtistImageUpdated(); void onAlbumsFound( const QList& albums, Tomahawk::ModelMode mode ); + void onTracksFound( const QList& queries, Tomahawk::ModelMode mode ); + void onSimilarArtistsLoaded(); void onLoadingStarted(); void onLoadingFinished(); From d2f876b6f3d7b2012338c7cd97c436745708eb43 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 27 May 2012 13:09:22 -0400 Subject: [PATCH 117/433] Only load resolve icon pixmap once --- src/libtomahawk/jobview/PipelineStatusItem.cpp | 15 +++++++++++++-- src/libtomahawk/jobview/PipelineStatusItem.h | 5 +++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/jobview/PipelineStatusItem.cpp b/src/libtomahawk/jobview/PipelineStatusItem.cpp index 779287789..556b9a41d 100644 --- a/src/libtomahawk/jobview/PipelineStatusItem.cpp +++ b/src/libtomahawk/jobview/PipelineStatusItem.cpp @@ -27,12 +27,11 @@ #include "JobStatusView.h" #include "Source.h" +QPixmap* PipelineStatusItem::s_pixmap = 0; PipelineStatusItem::PipelineStatusItem() : JobStatusItem() { - m_icon.load( RESPATH"images/search-icon.png" ); - connect( Tomahawk::Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), this, SLOT( resolving( Tomahawk::query_ptr ) ) ); connect( Tomahawk::Pipeline::instance(), SIGNAL( idle() ), this, SLOT( idle() ) ); } @@ -65,6 +64,18 @@ PipelineStatusItem::idle() } +QPixmap +PipelineStatusItem::icon() const +{ + if ( !s_pixmap ) + { + s_pixmap = new QPixmap( RESPATH"images/search-icon.png" ); + } + + return *s_pixmap; +} + + void PipelineStatusItem::resolving( const Tomahawk::query_ptr& query ) { diff --git a/src/libtomahawk/jobview/PipelineStatusItem.h b/src/libtomahawk/jobview/PipelineStatusItem.h index a1d7db719..da95e96fd 100644 --- a/src/libtomahawk/jobview/PipelineStatusItem.h +++ b/src/libtomahawk/jobview/PipelineStatusItem.h @@ -33,7 +33,7 @@ public: virtual QString rightColumnText() const; virtual QString mainText() const; - virtual QPixmap icon() const { return m_icon; } + virtual QPixmap icon() const; virtual QString type() const { return "pipeline"; } @@ -44,8 +44,9 @@ private slots: void idle(); private: - QPixmap m_icon; QString m_latestQuery; + + static QPixmap* s_pixmap; }; class PipelineStatusManager : public QObject From aee7dcd008499f59e90d3dadd966ed6b373b32f3 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 27 May 2012 13:09:33 -0400 Subject: [PATCH 118/433] More debug an an assert to track down empty resolve status job --- src/libtomahawk/jobview/PipelineStatusItem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libtomahawk/jobview/PipelineStatusItem.cpp b/src/libtomahawk/jobview/PipelineStatusItem.cpp index 556b9a41d..03296b48b 100644 --- a/src/libtomahawk/jobview/PipelineStatusItem.cpp +++ b/src/libtomahawk/jobview/PipelineStatusItem.cpp @@ -84,6 +84,10 @@ PipelineStatusItem::resolving( const Tomahawk::query_ptr& query ) else m_latestQuery = QString( "%1 - %2" ).arg( query->artist() ).arg( query->track() ); + if ( m_latestQuery.isEmpty() ) + qDebug() << "EMPTY STRING IN STATUS ITEM:" << query->fullTextQuery() << query->track() << query->artist() << query->album(); + Q_ASSERT( !m_latestQuery.isEmpty() ); + emit statusChanged(); } From 401d52d6f05de2f7ea6f4ba2ecda10c3671f3cfa Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:19:29 +0200 Subject: [PATCH 119/433] * Remove obsolete info-id. --- src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp | 1 - src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 4131f3a6d..99aebceac 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -43,7 +43,6 @@ using namespace Tomahawk; AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* parent ) : QWidget( parent ) , ui( new Ui::AlbumInfoWidget ) - , m_infoId( uuid() ) { ui->setupUi( this ); diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h index 9cc4f9ccd..43bcfbfa3 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h @@ -111,8 +111,6 @@ private: QString m_description; QString m_longDescription; QPixmap m_pixmap; - - QString m_infoId; }; #endif // ALBUMINFOWIDGET_H From 13befb9d6f70fa960ba5135cadc15c910efc6f9e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:19:44 +0200 Subject: [PATCH 120/433] * Remove obsolete info-id. --- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp | 1 - src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 15a696185..dbc0244ba 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -35,7 +35,6 @@ using namespace Tomahawk; TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* parent ) : QWidget( parent ) , ui( new Ui::TrackInfoWidget ) - , m_infoId( uuid() ) { ui->setupUi( this ); QPalette pal = palette(); diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h index 691ea43b7..1a1f7c341 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h @@ -91,7 +91,6 @@ private: AlbumModel* m_relatedTracksModel; QString m_title; QPixmap m_pixmap; - QString m_infoId; }; #endif // TRACKINFOWIDGET_H From 9af174a198b5f660a8dd002fecf542f82d3236b5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:21:00 +0200 Subject: [PATCH 121/433] * Use new API in TopTracksContext. --- .../context/pages/TopTracksContext.cpp | 72 ++++--------------- .../context/pages/TopTracksContext.h | 5 +- 2 files changed, 14 insertions(+), 63 deletions(-) diff --git a/src/libtomahawk/context/pages/TopTracksContext.cpp b/src/libtomahawk/context/pages/TopTracksContext.cpp index 585146360..2635f7c2b 100644 --- a/src/libtomahawk/context/pages/TopTracksContext.cpp +++ b/src/libtomahawk/context/pages/TopTracksContext.cpp @@ -29,7 +29,6 @@ using namespace Tomahawk; TopTracksContext::TopTracksContext() : ContextPage() - , m_infoId( uuid() ) { m_topHitsView = new PlaylistView(); m_topHitsView->setGuid( "TopTracksContext" ); @@ -45,12 +44,6 @@ TopTracksContext::TopTracksContext() m_proxy = new QGraphicsProxyWidget(); m_proxy->setWidget( m_topHitsView ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); } @@ -67,18 +60,19 @@ TopTracksContext::setArtist( const Tomahawk::artist_ptr& artist ) if ( !m_artist.isNull() && m_artist->name() == artist->name() ) return; + if ( !m_artist.isNull() ) + { + disconnect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + this, SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); + } + m_artist = artist; - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist->name(); + connect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), + SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_infoId; - requestData.customData = QVariantMap(); - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSongs; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + m_topHitsModel->clear(); + onTracksFound( m_artist->tracks(), Mixed ); } @@ -103,51 +97,11 @@ TopTracksContext::setQuery( const Tomahawk::query_ptr& query ) void -TopTracksContext::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +TopTracksContext::onTracksFound( const QList& queries, ModelMode mode ) { - if ( requestData.caller != m_infoId ) - return; + Q_UNUSED( mode ); - InfoSystem::InfoStringHash trackInfo; - trackInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - - if ( output.canConvert< QVariantMap >() ) - { - if ( trackInfo["artist"] != m_artist->name() ) - { - qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name(); - return; - } - } - - QVariantMap returnedData = output.value< QVariantMap >(); - switch ( requestData.type ) - { - case InfoSystem::InfoArtistSongs: - { - m_topHitsModel->clear(); - const QStringList tracks = returnedData["tracks"].toStringList(); - - int i = 0; - foreach ( const QString& track, tracks ) - { - query_ptr query = Query::get( m_artist->name(), track, QString(), uuid() ); - m_topHitsModel->append( query ); - - if ( ++i == 15 ) - break; - } - break; - } - - default: - return; - } + m_topHitsModel->append( queries ); } -void -TopTracksContext::infoSystemFinished( QString target ) -{ - Q_UNUSED( target ); -} diff --git a/src/libtomahawk/context/pages/TopTracksContext.h b/src/libtomahawk/context/pages/TopTracksContext.h index 662f00c02..bc8219b62 100644 --- a/src/libtomahawk/context/pages/TopTracksContext.h +++ b/src/libtomahawk/context/pages/TopTracksContext.h @@ -28,7 +28,6 @@ #include "Album.h" #include "Query.h" #include "context/ContextPage.h" -#include "infosystem/InfoSystem.h" class PlaylistModel; class PlaylistView; @@ -56,8 +55,7 @@ public slots: virtual void setQuery( const Tomahawk::query_ptr& query ); private slots: - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void infoSystemFinished( QString target ); + void onTracksFound( const QList& queries, Tomahawk::ModelMode mode ); private: PlaylistView* m_topHitsView; @@ -65,7 +63,6 @@ private: QGraphicsProxyWidget* m_proxy; - QString m_infoId; Tomahawk::artist_ptr m_artist; }; From 49a4dddd880968819887dafdee969cfd1a50258f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:21:16 +0200 Subject: [PATCH 122/433] * Use new API in RelatedArtistsContext. --- .../context/pages/RelatedArtistsContext.cpp | 59 ++++--------------- .../context/pages/RelatedArtistsContext.h | 5 +- 2 files changed, 12 insertions(+), 52 deletions(-) diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp index 23f54d2f4..41ab75a2f 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp @@ -30,7 +30,6 @@ using namespace Tomahawk; RelatedArtistsContext::RelatedArtistsContext() : ContextPage() - , m_infoId( uuid() ) { m_relatedView = new ArtistView(); m_relatedView->setGuid( "RelatedArtistsContext" ); @@ -70,18 +69,17 @@ RelatedArtistsContext::setArtist( const Tomahawk::artist_ptr& artist ) if ( !m_artist.isNull() && m_artist->name() == artist->name() ) return; + if ( !m_artist.isNull() ) + { + disconnect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), this, SLOT( onSimilarArtistsLoaded() ) ); + } + m_artist = artist; - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist->name(); + connect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), SLOT( onSimilarArtistsLoaded() ) ); - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_infoId; - requestData.customData = QVariantMap(); - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSimilars; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + m_relatedModel->clear(); + onSimilarArtistsLoaded(); } @@ -106,45 +104,10 @@ RelatedArtistsContext::setAlbum( const Tomahawk::album_ptr& album ) void -RelatedArtistsContext::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +RelatedArtistsContext::onSimilarArtistsLoaded() { - if ( requestData.caller != m_infoId ) - return; - - InfoSystem::InfoStringHash trackInfo; - trackInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - - if ( output.canConvert< QVariantMap >() ) + foreach ( const artist_ptr& artist, m_artist->similarArtists() ) { - if ( trackInfo["artist"] != m_artist->name() ) - { - qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name(); - return; - } - } - - QVariantMap returnedData = output.value< QVariantMap >(); - switch ( requestData.type ) - { - case InfoSystem::InfoArtistSimilars: - { - m_relatedModel->clear(); - const QStringList artists = returnedData["artists"].toStringList(); - foreach ( const QString& artist, artists ) - { - m_relatedModel->addArtists( Artist::get( artist ) ); - } - break; - } - - default: - return; + m_relatedModel->addArtists( artist ); } } - - -void -RelatedArtistsContext::infoSystemFinished( QString target ) -{ - Q_UNUSED( target ); -} diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.h b/src/libtomahawk/context/pages/RelatedArtistsContext.h index 53d3c9a5e..c87b25630 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.h +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.h @@ -28,7 +28,6 @@ #include "Album.h" #include "Query.h" #include "context/ContextPage.h" -#include "infosystem/InfoSystem.h" class TreeModel; class ArtistView; @@ -56,8 +55,7 @@ public slots: virtual void setQuery( const Tomahawk::query_ptr& query ); private slots: - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void infoSystemFinished( QString target ); + void onSimilarArtistsLoaded(); private: ArtistView* m_relatedView; @@ -65,7 +63,6 @@ private: QGraphicsProxyWidget* m_proxy; - QString m_infoId; Tomahawk::artist_ptr m_artist; }; From b3f2478d6d1bb24b8444f347dd8fa411c3a8d8b8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:31:00 +0200 Subject: [PATCH 123/433] * Remove debug output again. --- src/libtomahawk/Source.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index 42733a370..53f46bf32 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -135,7 +135,6 @@ Source::setAvatar( const QPixmap& avatar ) buffer.open( QIODevice::WriteOnly ); avatar.save( &buffer, "PNG" ); - tDebug() << Q_FUNC_INFO << friendlyName() << m_username << ba.count(); TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, m_username, ba ); m_avatarUpdated = true; } From c2814bdabb7c199c602e5ca38c858dd80b7f607f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:35:09 +0200 Subject: [PATCH 124/433] * Make hover fading a tiny bit faster again. --- src/libtomahawk/playlist/AlbumItemDelegate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index d1f6419df..7899cc7be 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -44,7 +44,7 @@ #include "utils/Logger.h" namespace { - static const int FADE_DURATION = 250; + static const int FADE_DURATION = 200; }; From f7a46de38eb2ce585005eb6dd6e71df150120403 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 19:43:58 +0200 Subject: [PATCH 125/433] * Remove bottom frame of our toolbar. --- src/TomahawkWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 7a288ac9f..9ef331c0a 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -213,7 +213,8 @@ TomahawkWindow::setupToolBar() toolbar->setFloatable( false ); toolbar->setIconSize( QSize( 22, 22 ) ); toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly ); - + toolbar->setStyleSheet( "border-bottom: 0px" ); + #ifdef Q_OS_MAC toolbar->installEventFilter( new WidgetDragFilter( toolbar ) ); #endif From 04ce45368724e1b835094808bf474c85a54c4ce0 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 27 May 2012 20:26:46 +0200 Subject: [PATCH 126/433] * Fixed TWK-910: Make sure search results are sorted properly. --- .../playlist/PlayableProxyModel.cpp | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libtomahawk/playlist/PlayableProxyModel.cpp b/src/libtomahawk/playlist/PlayableProxyModel.cpp index efee2a979..aec3abf87 100644 --- a/src/libtomahawk/playlist/PlayableProxyModel.cpp +++ b/src/libtomahawk/playlist/PlayableProxyModel.cpp @@ -161,19 +161,20 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right const Tomahawk::query_ptr& q1 = p1->query()->displayQuery(); const Tomahawk::query_ptr& q2 = p2->query()->displayQuery(); - QString artist1 = q1->artistSortname(); - QString artist2 = q2->artistSortname(); - QString album1 = q1->albumSortname(); - QString album2 = q2->albumSortname(); - QString track1 = q1->trackSortname(); - QString track2 = q2->trackSortname(); - unsigned int albumpos1 = q1->albumpos(); - unsigned int albumpos2 = q2->albumpos(); - unsigned int discnumber1 = q1->discnumber(); - unsigned int discnumber2 = q2->discnumber(); + const QString artist1 = q1->artistSortname(); + const QString artist2 = q2->artistSortname(); + const QString album1 = q1->albumSortname(); + const QString album2 = q2->albumSortname(); + const QString track1 = q1->trackSortname(); + const QString track2 = q2->trackSortname(); + const unsigned int albumpos1 = q1->albumpos(); + const unsigned int albumpos2 = q2->albumpos(); + const unsigned int discnumber1 = q1->discnumber(); + const unsigned int discnumber2 = q2->discnumber(); unsigned int bitrate1 = 0, bitrate2 = 0; unsigned int mtime1 = 0, mtime2 = 0; unsigned int size1 = 0, size2 = 0; + float score1 = 0, score2 = 0; qint64 id1 = 0, id2 = 0; if ( q1->numResults() ) @@ -181,16 +182,18 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right const Tomahawk::result_ptr& r = q1->results().at( 0 ); bitrate1 = r->bitrate(); mtime1 = r->modificationTime(); - id1 = r->trackId(); size1 = r->size(); + score1 = r->score(); + id1 = (qint64)&r; } if ( q2->numResults() ) { const Tomahawk::result_ptr& r = q2->results().at( 0 ); bitrate2 = r->bitrate(); mtime2 = r->modificationTime(); - id2 = r->trackId(); size2 = r->size(); + score2 = r->score(); + id2 = (qint64)&r; } // This makes it a stable sorter and prevents items from randomly jumping about. From f3164635e06ee103e9f466cc2b58797b277ac343 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sun, 27 May 2012 22:16:53 +0000 Subject: [PATCH 127/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_bg.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_ca.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_de.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_en.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_es.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_fr.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_ja.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_pl.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_pt_BR.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_ru.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_sv.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_tr.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_zh_CN.ts | 160 +++++++++++++++++++++-------------------- lang/tomahawk_zh_TW.ts | 160 +++++++++++++++++++++-------------------- 15 files changed, 1260 insertions(+), 1140 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 7b81883a0..489ef9ad2 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -134,7 +134,7 @@ connect and stream from you? ألبومات أخرى للفنان - + Other Albums by %1 ألبومات أخرى ل%1 @@ -510,24 +510,6 @@ connect and stream from you? مرشح... - - JobStatusView - - - Searching For - تفتيش عن - - - - Pending - انتظار - - - - Idle - عاطلة - - LastFmConfig @@ -1004,7 +986,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists الفنانين ذات الذوق القريب @@ -1287,27 +1269,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &نسخ الرابط - + &Delete %1 &أحذف %1 - + Add to my Playlists أضف إلى لوائحي للأغاني - + Add to my Automatic Playlists أضف إلى لوائحي الأوتوماتيكية للأغاني - + Add to my Stations أضف إلى إذاعاتي @@ -1317,12 +1299,38 @@ connect and stream from you? &تصدير قائمة الأغاني - + + playlist + قائمة الأغاني + + + + automatic playlist + قائمة أغاني أوتوماتيكية + + + + station + إذاعة + + + + Delete %1? + playlist/station/... + أحذف %1؟ + + + + Would you like to delete the %1 <b>"%2"</b>? + هل ترغب في حذف %1 <b> "%2" </b>؟ + + + Save XSPF حفظ XSPF - + Playlists (*.xspf) قوائم أغاني (*.xspf) @@ -2725,33 +2733,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) يجري مسح (%L1 أغنية) - + Scanning مسح - + Checking فحص - + Fetching جلب - + Parsing تحليل - + Saving (%1%) تحفيظ(%1%) @@ -2973,7 +2981,7 @@ enter the displayed PIN number here: - + Play إستمع @@ -2993,167 +3001,167 @@ enter the displayed PIN number here: التالي - + Back إلى الوراء - + Go back one page العودة صفحة واحدة إلى الوراء - + Forward تقدم - + Go forward one page تقدم صفحة واحدة - + Global Search... بحث شامل... - - + + Check For Updates... التحقق من التحديثات... - - - + + + Connect To Peer ربط بالند - + Enter peer address: أدخل عنوان الند: - + Enter peer port: أدخل بوابة الند: - + Enter peer key: أدخل مفتاح الند: - + XSPF Error خطأ XSPF - + This is not a valid XSPF playlist. قائمة الأغاني XSPF هذه ليست صالحة. - + Failed to save tracks فشل في حفظ الأغاني - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. - + Create New Station إنشاء قائمة أغاني جديدة - + Name: الاسم: - + New Station إذاعة جديدة - + New Playlist قائمة أغاني جديدة - + Pause تعليق - + Go &offline إذهب &خارج الهواء - + Go &online إذهب &على الهواء - + Authentication Error خطأ في المصادقة - + Error connecting to SIP: Authentication failed! خطأ في الاتصال بسيب (SIP): فشلت المصادقة! - + %1 by %2 track, artist name %1 من قبل %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ - + Thanks to: شكر لكل من: - + About Tomahawk عن توماهوك @@ -3224,7 +3232,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits الأكثر شهرة @@ -3472,27 +3480,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection سوبر كولكشن - + Combined libraries of all your online friends جمع مكاتب أصدقائك الذين على الهواء - + All available albums جميع الألبومات الجديدة - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Recently played tracks from all your friends جميع الأغاني التي استمع إليها أصدقائك مؤخرا diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 25d122339..ade16ac2f 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -133,7 +133,7 @@ connect and stream from you? Други албуми на този артист - + Other Albums by %1 Други албуми от %1 @@ -513,24 +513,6 @@ Tomahaw създаде доклад относно това и изпращай Филтър... - - JobStatusView - - - Searching For - Търсене за - - - - Pending - Изчакващо - - - - Idle - Бездействам - - LastFmConfig @@ -1005,7 +987,7 @@ Tomahaw създаде доклад относно това и изпращай RelatedArtistsContext - + Related Artists Подобни артисти @@ -1289,27 +1271,27 @@ Tomahaw създаде доклад относно това и изпращай SourceTreeView - + &Copy Link &Копирай адресът - + &Delete %1 &Изтрий %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1319,12 +1301,38 @@ Tomahaw създаде доклад относно това и изпращай &Изнеси списък - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -2733,33 +2741,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканиране (%L1 песни) - + Scanning Сканирам - + Checking Проверявам - + Fetching Извличам - + Parsing Сортирам - + Saving (%1%) Запазвам (%1%) @@ -2981,7 +2989,7 @@ enter the displayed PIN number here: - + Play Изпълни @@ -3001,170 +3009,170 @@ enter the displayed PIN number here: Следваща - + Back - + Go back one page Една страница назад - + Forward Напред - + Go forward one page Една страница напред - + Global Search... Глобално търсене... - - + + Check For Updates... Провери за обновления... - - - + + + Connect To Peer Свържи се с друг потребител - + Enter peer address: Въведи адресът на отдалеченият потребител: - + Enter peer port: Въведи порт: - + Enter peer key: Въведи ключът за удостоверяване: - + XSPF Error XSPF Грешка - + This is not a valid XSPF playlist. Това не е валиден XSPF списък - + Failed to save tracks Не мога да запазя списъкът с песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Някои от песните в този списък нямат артист и заглавие. Те ще бъдат игнорирани. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраната песен - тя ще бъде прескочена. Моля, увери се, че са инсталирани подходящ Phonon и приставки. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Съжалявам. Има проблем с достъпа до твоето аудио устройство или избраната песен. Тя ще бъде пропусната. - + Create New Station Създай нова станция - + Name: Име: - + New Station Нова станция - + New Playlist Нов списък - + Pause Пауза - + Go &offline Излез &извън линия - + Go &online Свържи &се - + Authentication Error Грешка при удостоверяване - + Error connecting to SIP: Authentication failed! Грешка при свързване: Неуспешно удостоверяване! - + %1 by %2 track, artist name %1 от %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Всички права - запазени. 2010 - 2012 - + Thanks to: Благодарности на: - + About Tomahawk Относно Tomahawk @@ -3235,7 +3243,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits Най-слушани @@ -3484,28 +3492,28 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Combined libraries of all your online friends Обща колекция с всичките ми приятели на линия - + All available albums Всички налични албуми - + Recently Played Tracks Наскоро изпълени песни - + Recently played tracks from all your friends Наскоро изпълнени песни от всичките ти приятели diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 626df66fb..cb29b0708 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -133,7 +133,7 @@ connect and stream from you? Altres Àlbums de l'Artista - + Other Albums by %1 Altres Àlbums de %1 @@ -509,24 +509,6 @@ connect and stream from you? Filtra... - - JobStatusView - - - Searching For - Cercant - - - - Pending - Pendent - - - - Idle - Inactiu - - LastFmConfig @@ -1002,7 +984,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Artistes Relacionats @@ -1285,27 +1267,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copia l'Enllaç - + &Delete %1 &Esborra %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1315,12 +1297,38 @@ connect and stream from you? E&xporta la Llista de Reproducció - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -2724,33 +2732,33 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::Source - - + + Scanning (%L1 tracks) Escanejant (%L1 cançons) - + Scanning Escanejant - + Checking Comprovant - + Fetching Cercant - + Parsing Analitzant - + Saving (%1%) Desant (%1%) @@ -2972,7 +2980,7 @@ introduïu el PIN aquí: - + Play Reprodueix @@ -2992,167 +3000,167 @@ introduïu el PIN aquí: Següent - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Cerca Global... - - + + Check For Updates... Comprova les actualitzacions... - - - + + + Connect To Peer Connexió Remota - + Enter peer address: Introduïu l'adreça remota: - + Enter peer port: Introduïu el port remot: - + Enter peer key: Introduïu la clau remota: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. No és una llista XSPF vàlida. - + Failed to save tracks Error en desar les cançons - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunes cançons de la llista no contenen ni artista ni titol i s'han ignorat. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Hi ha un problema per accedir al dispositiu de so o a la cançó. La cançó actual s'ha saltat. Assegureu-vos que teniu un back.end de Phonon adequant i els plugins necessaris instal·lats. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Hi ha un problema per accedir al dispositiu de so o a la cançó, la cançó actual s'ha saltat. - + Create New Station Crea una Nova Emissora - + Name: Nom: - + New Station Nova Emissora - + New Playlist Nova llista de reproducció - + Pause Pausa - + Go &offline &Desconnecta't - + Go &online &Connecta't - + Authentication Error Error d'autentificació - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Quant a Tomahawk @@ -3223,7 +3231,7 @@ introduïu el PIN aquí: TopTracksContext - + Top Hits Grans Èxits @@ -3471,27 +3479,27 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant ViewManager - + SuperCollection SuperCol·lecció - + Combined libraries of all your online friends Biblioteques combinades de tots els amis en línia - + All available albums Tots els àlbums disponibles - + Recently Played Tracks Cançons Escoltades Recentment - + Recently played tracks from all your friends Cançons escoltades recentment pels amics diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 885639a56..e3d37a125 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -133,7 +133,7 @@ connect and stream from you? Andere Alben des Künstlers - + Other Albums by %1 Andere Alben von %1 @@ -509,24 +509,6 @@ connect and stream from you? Filter... - - JobStatusView - - - Searching For - Suche nach - - - - Pending - Verbleibend - - - - Idle - Warte - - LastFmConfig @@ -1002,7 +984,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Ähnliche Künstler @@ -1285,27 +1267,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiere Link - + &Delete %1 &Lösche %1 - + Add to my Playlists Zu meinen Playlisten hinzufügen - + Add to my Automatic Playlists Zu meinen Automatischen Playlisten hinzufügen - + Add to my Stations Zu meinen Stationen hinzufügen @@ -1315,12 +1297,38 @@ connect and stream from you? Playliste &exportieren - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -2719,33 +2727,33 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanne (%L1 Stücke) - + Scanning Scanne - + Checking Überprüfe - + Fetching Sammle - + Parsing Parse - + Saving (%1%) Speichere (%1%) @@ -2967,7 +2975,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: - + Play Abspielen @@ -2987,167 +2995,167 @@ Tomahawk auf Twitter's Website authentifiziert hast: Weiter - + Back Zurück - + Go back one page Gehe eine Seite zurück - + Forward Vorwärts - + Go forward one page Gehe eine Seite vorwärts - + Global Search... Globale Suche... - - + + Check For Updates... Nach Updates suchen... - - - + + + Connect To Peer Mit anderem Tomahawk verbinden - + Enter peer address: Gib die Adresse der Gegenstelle ein: - + Enter peer port: Gib den Port der Gegenstelle ein: - + Enter peer key: Gib den Schlüssel der Gegenstelle ein: - + XSPF Error XSPF-Fehler - + This is not a valid XSPF playlist. Dies ist keine gültige XSPF-Playliste. - + Failed to save tracks Konnte Stücke nicht abspeichern - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Einige Stücke in der Playliste enthalten weder Künstler noch Titel. Diese werden ignoriert. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. Vergewisser dich, dass ein geignetes Phonon-Backend mitsamt benötigten Plugins installiert ist. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. - + Create New Station Neue Station erstellen - + Name: Name: - + New Station Neue Station - + New Playlist Neue Playliste - + Pause Pause - + Go &offline Verbindung &trennen - + Go &online &Verbindung herstellen - + Authentication Error Authentifizierungsfehler - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 von %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Über Tomahawk @@ -3218,7 +3226,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: TopTracksContext - + Top Hits Top Hits @@ -3461,27 +3469,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Kombinierte Sammlung all deiner Freunde - + All available albums Alle verfügbaren Alben - + Recently Played Tracks Zuletzt gehörte Lieder - + Recently played tracks from all your friends Zuletzt gehörte Lieder all deiner Freunde diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 8b209d8a8..e524091ae 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -134,7 +134,7 @@ connect and stream from you? Other Albums by Artist - + Other Albums by %1 Other Albums by %1 @@ -510,24 +510,6 @@ connect and stream from you? Filter... - - JobStatusView - - - Searching For - Searching For - - - - Pending - Pending - - - - Idle - Idle - - LastFmConfig @@ -1003,7 +985,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Related Artists @@ -1286,27 +1268,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copy Link - + &Delete %1 &Delete %1 - + Add to my Playlists Add to my Playlists - + Add to my Automatic Playlists Add to my Automatic Playlists - + Add to my Stations Add to my Stations @@ -1316,12 +1298,38 @@ connect and stream from you? &Export Playlist - + + playlist + playlist + + + + automatic playlist + automatic playlist + + + + station + station + + + + Delete %1? + playlist/station/... + Delete %1? + + + + Would you like to delete the %1 <b>"%2"</b>? + Would you like to delete the %1 <b>"%2"</b>? + + + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -2725,33 +2733,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanning (%L1 tracks) - + Scanning Scanning - + Checking Checking - + Fetching Fetching - + Parsing Parsing - + Saving (%1%) Saving (%1%) @@ -2973,7 +2981,7 @@ enter the displayed PIN number here: - + Play Play @@ -2993,167 +3001,167 @@ enter the displayed PIN number here: Next - + Back Back - + Go back one page Go back one page - + Forward Forward - + Go forward one page Go forward one page - + Global Search... Global Search... - - + + Check For Updates... Check For Updates... - - - + + + Connect To Peer Connect To Peer - + Enter peer address: Enter peer address: - + Enter peer port: Enter peer port: - + Enter peer key: Enter peer key: - + XSPF Error XSPF Error - + This is not a valid XSPF playlist. This is not a valid XSPF playlist. - + Failed to save tracks Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Create New Station - + Name: Name: - + New Station New Station - + New Playlist New Playlist - + Pause Pause - + Go &offline Go &offline - + Go &online Go &online - + Authentication Error Authentication Error - + Error connecting to SIP: Authentication failed! Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Copyright 2010 - 2012 - + Thanks to: Thanks to: - + About Tomahawk About Tomahawk @@ -3224,7 +3232,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits Top Hits @@ -3472,27 +3480,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Combined libraries of all your online friends - + All available albums All available albums - + Recently Played Tracks Recently Played Tracks - + Recently played tracks from all your friends Recently played tracks from all your friends diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index d38dfd11a..b720e24ef 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -133,7 +133,7 @@ connect and stream from you? Otros álbumes por el artista - + Other Albums by %1 Otros álbumes por %1 @@ -509,24 +509,6 @@ connect and stream from you? Filtro... - - JobStatusView - - - Searching For - Buscando por - - - - Pending - Pendiente - - - - Idle - Ocupado - - LastFmConfig @@ -1001,7 +983,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Artistas relacionados @@ -1284,27 +1266,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copiar enlace - + &Delete %1 &Eliminar %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1314,12 +1296,38 @@ connect and stream from you? &Exportar lista de reproducción - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -2723,33 +2731,33 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 pistas) - + Scanning Escaneando - + Checking Comprobando - + Fetching Obteniendo - + Parsing Analizando - + Saving (%1%) Guardando (%1%) @@ -2971,7 +2979,7 @@ introduzca su número PIN aquí: - + Play Reproducir @@ -2991,167 +2999,167 @@ introduzca su número PIN aquí: Siguiente - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Búsqueda global... - - + + Check For Updates... Buscar actualizaciones... - - - + + + Connect To Peer Conectar a un par - + Enter peer address: Introducir dirección del par: - + Enter peer port: Introducir puerto del par: - + Enter peer key: Introducir contraseña del par: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. Esta no es una lista de reproducción XSPF válida. - + Failed to save tracks Fallo al guardar pistas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunas pistas en la lista de reproducción no contienen artista ni título. Serán ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. Asegúrese de que ha instalado un backend de Phonon adecuado y los plugins necesarios. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. - + Create New Station Crear nueva estación - + Name: Nombre: - + New Station Nueva estación - + New Playlist Nueva lista de reproducción - + Pause Pausar - + Go &offline &Desconectarse - + Go &online &Conectarse - + Authentication Error Error de autenticación - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 por %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Acerca de Tomahawk @@ -3222,7 +3230,7 @@ introduzca su número PIN aquí: TopTracksContext - + Top Hits Grandes éxitos @@ -3470,27 +3478,27 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en ViewManager - + SuperCollection SuperColección - + Combined libraries of all your online friends Bibliotecas combinadas de todos tus amigos conectados - + All available albums Todos los álbumes disponibles - + Recently Played Tracks Temas Escuchados Recientemente - + Recently played tracks from all your friends Temas escuchados recientemente por mis amigos diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index e65bf897f..cc9a6ef86 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -134,7 +134,7 @@ se connecter et streamer depuis chez vous ? Tous les albums par cet artiste - + Other Albums by %1 Autres albums par %1 @@ -510,24 +510,6 @@ se connecter et streamer depuis chez vous ? Filtre... - - JobStatusView - - - Searching For - Recherche de - - - - Pending - En suspens - - - - Idle - Pas d'activité - - LastFmConfig @@ -1003,7 +985,7 @@ se connecter et streamer depuis chez vous ? RelatedArtistsContext - + Related Artists Artistes similaires @@ -1286,27 +1268,27 @@ se connecter et streamer depuis chez vous ? SourceTreeView - + &Copy Link &Copier le lien - + &Delete %1 &Supprimer %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1316,12 +1298,38 @@ se connecter et streamer depuis chez vous ? &Exporter la liste de lecture - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -2725,33 +2733,33 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Source - - + + Scanning (%L1 tracks) Scan en cours (%L1 titres) - + Scanning Scan en cours - + Checking Vérification - + Fetching Chargement - + Parsing Décodage - + Saving (%1%) Enregistrement (%1%) @@ -2973,7 +2981,7 @@ saisissez le numéro PIN ici : - + Play Lecture @@ -2993,167 +3001,167 @@ saisissez le numéro PIN ici : Suivant - + Back Retour - + Go back one page Reculer d'une page - + Forward Avancer - + Go forward one page Avancer d'une page - + Global Search... Recherche Globale... - - + + Check For Updates... Rechercher une mise à jour... - - - + + + Connect To Peer Connexion à un pair - + Enter peer address: Adresse du pair : - + Enter peer port: Port du pair : - + Enter peer key: Clé du pair : - + XSPF Error Erreur XSPF - + This is not a valid XSPF playlist. Ceci n'est pas une liste de lecture XSPF valide. - + Failed to save tracks Échec de la sauvegarde des pistes - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. - + Create New Station Créer une nouvelle station - + Name: Nom : - + New Station Nouvelle station - + New Playlist Nouvelle liste de lecture - + Pause Pause - + Go &offline Se &déconnecter - + Go &online Se c&onnecter - + Authentication Error Erreur d'authentification - + Error connecting to SIP: Authentication failed! Erreur de connexion SIP : échec de l'authentification ! - + %1 by %2 track, artist name %1 par %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk A propos de Tomahawk @@ -3224,7 +3232,7 @@ saisissez le numéro PIN ici : TopTracksContext - + Top Hits Top Hits @@ -3472,27 +3480,27 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env ViewManager - + SuperCollection SuperCollection - + Combined libraries of all your online friends Collections regroupant toutes celles de vos amis en ligne - + All available albums Tous les albums disponibles - + Recently Played Tracks Derniers titres joués - + Recently played tracks from all your friends Derniers titres joués par vos amis diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 540692745..6a48bd4d9 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -133,7 +133,7 @@ connect and stream from you? 他のアルバム - + Other Albums by %1 %1の他のアルバム @@ -509,24 +509,6 @@ connect and stream from you? フィルター... - - JobStatusView - - - Searching For - 検索中 - - - - Pending - 保留中 - - - - Idle - 待機中 - - LastFmConfig @@ -1008,7 +990,7 @@ other: %n週間前 RelatedArtistsContext - + Related Artists @@ -1291,27 +1273,27 @@ other: %n週間前 SourceTreeView - + &Copy Link リンクをコピー - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1321,12 +1303,38 @@ other: %n週間前 - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -2720,33 +2728,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning 走査中 - + Checking - + Fetching 取得中 - + Parsing 解析中 - + Saving (%1%) @@ -2967,7 +2975,7 @@ enter the displayed PIN number here: - + Play @@ -2987,167 +2995,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station 新規ステーションを作成 - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3218,7 +3226,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3461,27 +3469,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 667212a20..9472b83e6 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -133,7 +133,7 @@ connect and stream from you? Inne albumy artysty - + Other Albums by %1 Inne albumy %1 @@ -509,24 +509,6 @@ connect and stream from you? Filtruj... - - JobStatusView - - - Searching For - Szukanie - - - - Pending - w trakcie - - - - Idle - Bezczynny - - LastFmConfig @@ -1001,7 +983,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Podobni Artyści @@ -1284,27 +1266,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiuj Link - + &Delete %1 &Usuń %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1314,12 +1296,38 @@ connect and stream from you? &Eksportuj Listę - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -2719,33 +2727,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Skanowanie (%L1 utworów) - + Scanning Skanowanie - + Checking Sprawdzanie - + Fetching Pobieranie - + Parsing Analizowanie - + Saving (%1%) Zapisywanie (%1%) @@ -2967,7 +2975,7 @@ wprowadź pokazany numer PIN tutaj: - + Play Odtwarzaj @@ -2987,167 +2995,167 @@ wprowadź pokazany numer PIN tutaj: Następny - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Globalne Wyszukiwanie... - - + + Check For Updates... Sprawdź uaktualnienia... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error Błąd XSPF - + This is not a valid XSPF playlist. To nie jest poprawna lista XSPF. - + Failed to save tracks Nie udało się zapisać utworów - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Niektóre utwory na liście nie zawierają artysty i tytułu. Zostaną one zignorowane. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Utwórz Nową Stację - + Name: Nazwa: - + New Station Nowa stacja - + New Playlist Nowa Lista - + Pause Pauza - + Go &offline Przejdź do trybu &offline - + Go &online Przejdź do trybu &online - + Authentication Error Błąd uwierzytelniania - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 wykonawcy %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3218,7 +3226,7 @@ wprowadź pokazany numer PIN tutaj: TopTracksContext - + Top Hits Hity na Topie @@ -3466,27 +3474,27 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl ViewManager - + SuperCollection SuperKolekcja - + Combined libraries of all your online friends Połączone biblioteki wszystkich twoich znajomych online - + All available albums Wszystkie dostępne albumy - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index fdbd225ce..929440cd9 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -133,7 +133,7 @@ connect and stream from you? Outros álbuns do artista - + Other Albums by %1 Outros álbuns por %1 @@ -509,24 +509,6 @@ connect and stream from you? Filtro... - - JobStatusView - - - Searching For - Buscando por - - - - Pending - Pendente - - - - Idle - Ocioso - - LastFmConfig @@ -1001,7 +983,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Artistas relacionados @@ -1284,27 +1266,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copiar link - + &Delete %1 &Eliminar %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1314,12 +1296,38 @@ connect and stream from you? &Exportar lista de reprodução - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -2718,33 +2726,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 faixas) - + Scanning Escaneando - + Checking Verificando - + Fetching Buscando - + Parsing Analisando - + Saving (%1%) Guardando (%1%) @@ -2966,7 +2974,7 @@ colocar o número PIN mostrado aqui: - + Play Reporduzir @@ -2986,167 +2994,167 @@ colocar o número PIN mostrado aqui: Próximo - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Busca global... - - + + Check For Updates... Buscar atualizações... - - - + + + Connect To Peer Conectar-se ao par - + Enter peer address: Coloque o endereço do par: - + Enter peer port: Coloque a porta do par: - + Enter peer key: Coloque a chave do par: - + XSPF Error Erro de XSPF - + This is not a valid XSPF playlist. Esta não é uma lista de reprodução XSPF válida. - + Failed to save tracks Falha ao salvar faixas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algumas faixas da lista de reprodução não contem artista e título. Estas serão ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Criar uma nova estação - + Name: Nome: - + New Station Nova estação - + New Playlist Nova lista de reprodução - + Pause Pausar - + Go &offline Desc&onectar - + Go &online C&onectar - + Authentication Error Erro de autenticação - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Sobre o Tomahawk @@ -3217,7 +3225,7 @@ colocar o número PIN mostrado aqui: TopTracksContext - + Top Hits Maiores sucessos @@ -3465,27 +3473,27 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Todos os álbuns disponíveis - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 16b5860b4..a89afa615 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -134,7 +134,7 @@ connect and stream from you? Другие альбомы артиста - + Other Albums by %1 Другие альбомы %1 @@ -510,24 +510,6 @@ connect and stream from you? Фильтр... - - JobStatusView - - - Searching For - Искать - - - - Pending - В ожидании - - - - Idle - Бездействие - - LastFmConfig @@ -1003,7 +985,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Похожие исполнители @@ -1286,27 +1268,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Скопировать Cсылку - + &Delete %1 &Удалить %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1316,12 +1298,38 @@ connect and stream from you? &Экспорт Плейлиста - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -2720,33 +2728,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканирование (%L1 песни) - + Scanning Сканирую - + Checking Проверяю - + Fetching Выбираю - + Parsing Анализирую - + Saving (%1%) Сохраняю (%1%) @@ -2967,7 +2975,7 @@ enter the displayed PIN number here: - + Play Играть @@ -2987,167 +2995,167 @@ enter the displayed PIN number here: Следующая - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Глобальный поиск - - + + Check For Updates... Проверить обновления... - - - + + + Connect To Peer Связаться с Peer - + Enter peer address: Введите адрес узла: - + Enter peer port: Введите адрес порта: - + Enter peer key: Введите адрес ключа: - + XSPF Error Ошибка XSPF - + This is not a valid XSPF playlist. Это не является допустимым XSPF плейлистом. - + Failed to save tracks Не удалось сохранить песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Некоторые треки в плейлисте не содержат исполнителя и название. Они будут проигнорированы. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Создать новую станцию - + Name: Имя: - + New Station Новая станция - + New Playlist Новый плейлист - + Pause Пауза - + Go &offline Отключиться - + Go &online Подлючиться - + Authentication Error Ошибка авторизации - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk О Tomahawk @@ -3218,7 +3226,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits Хиты @@ -3465,27 +3473,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection Общая коллекция - + Combined libraries of all your online friends Комбинированные библиотек всех ваших друзей онлайн - + All available albums Доступные альбомы - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 1bc76af39..0d2cfeec2 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -133,7 +133,7 @@ connect and stream from you? Andra album av artisten - + Other Albums by %1 Andra album av %1 @@ -509,24 +509,6 @@ connect and stream from you? Filter... - - JobStatusView - - - Searching For - Söker efter - - - - Pending - Väntar - - - - Idle - Overksam - - LastFmConfig @@ -1002,7 +984,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists Relaterade artister @@ -1285,27 +1267,27 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiera länk - + &Delete %1 &Ta bort %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1315,12 +1297,38 @@ connect and stream from you? &Exportera spellista - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -2714,33 +2722,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Söker igenom (%L1 spår) - + Scanning - + Checking Kontrollerar - + Fetching Hämtar - + Parsing Tolkar - + Saving (%1%) Sparar (%1%) @@ -2961,7 +2969,7 @@ enter the displayed PIN number here: - + Play Spela upp @@ -2981,167 +2989,167 @@ enter the displayed PIN number here: Nästa - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Global sökning... - - + + Check For Updates... Leta efter uppdateringar... - - - + + + Connect To Peer Anslut till klient - + Enter peer address: Ange klientadress: - + Enter peer port: Ange klientport: - + Enter peer key: Ange klientnyckel: - + XSPF Error XSPF-fel - + This is not a valid XSPF playlist. Detta är inte en giltig XSPF-spellista. - + Failed to save tracks Misslyckades med att spara spår - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Några spår i spellistan innehåller inte någon artist och titel. De kommer att ignoreras. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Skapa ny station - + Name: Namn: - + New Station Ny station - + New Playlist Ny spellista - + Pause Paus - + Go &offline Koppla &från - + Go &online A&nslut - + Authentication Error Autentiseringsfel - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 av %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3212,7 +3220,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3455,27 +3463,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums Alla tillgängliga album - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 624f042e5..968726d82 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -133,7 +133,7 @@ connect and stream from you? Sanatçının Diğer Albümleri - + Other Albums by %1 Diğer %1 Albümleri @@ -509,24 +509,6 @@ connect and stream from you? Filtre... - - JobStatusView - - - Searching For - Şunu Ara: - - - - Pending - Beklemede - - - - Idle - Boşta - - LastFmConfig @@ -1001,7 +983,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists @@ -1284,27 +1266,27 @@ connect and stream from you? SourceTreeView - + &Copy Link - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1314,12 +1296,38 @@ connect and stream from you? - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF - + Playlists (*.xspf) @@ -2713,33 +2721,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) @@ -2960,7 +2968,7 @@ enter the displayed PIN number here: - + Play @@ -2980,167 +2988,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3211,7 +3219,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3454,27 +3462,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 91e48c9d7..0ac831b28 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -133,7 +133,7 @@ connect and stream from you? 艺人的其他专辑 - + Other Albums by %1 %1 的其他专辑 @@ -509,24 +509,6 @@ connect and stream from you? - - JobStatusView - - - Searching For - - - - - Pending - - - - - Idle - - - LastFmConfig @@ -1001,7 +983,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists @@ -1284,27 +1266,27 @@ connect and stream from you? SourceTreeView - + &Copy Link - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1314,12 +1296,38 @@ connect and stream from you? - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF - + Playlists (*.xspf) @@ -2713,33 +2721,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) @@ -2960,7 +2968,7 @@ enter the displayed PIN number here: - + Play @@ -2980,167 +2988,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3211,7 +3219,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits @@ -3454,27 +3462,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection - + Combined libraries of all your online friends - + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index e426bff31..2096a8210 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -133,7 +133,7 @@ connect and stream from you? 列出演出者的其他專輯 - + Other Albums by %1 列出所有其他專輯,依 %1 @@ -509,24 +509,6 @@ connect and stream from you? 過濾器... - - JobStatusView - - - Searching For - 搜尋 - - - - Pending - - - - - Idle - 閒置 - - LastFmConfig @@ -1001,7 +983,7 @@ connect and stream from you? RelatedArtistsContext - + Related Artists 相關演出者 @@ -1284,27 +1266,27 @@ connect and stream from you? SourceTreeView - + &Copy Link 複製鏈接 - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations @@ -1314,12 +1296,38 @@ connect and stream from you? 匯出播放清單 - + + playlist + + + + + automatic playlist + + + + + station + + + + + Delete %1? + playlist/station/... + + + + + Would you like to delete the %1 <b>"%2"</b>? + + + + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -2713,33 +2721,33 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing 解析 - + Saving (%1%) @@ -2960,7 +2968,7 @@ enter the displayed PIN number here: - + Play 播放 @@ -2980,167 +2988,167 @@ enter the displayed PIN number here: 下一首 - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... 全域搜尋... - - + + Check For Updates... 檢查更新... - - - + + + Connect To Peer 連接點對點 - + Enter peer address: 輸入對等地址: - + Enter peer port: 輸入對等連接埠: - + Enter peer key: 輸入對等密鑰: - + XSPF Error XSPF 錯誤 - + This is not a valid XSPF playlist. - + Failed to save tracks 無法儲存曲目 - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: 名稱: - + New Station - + New Playlist 新增播放清單 - + Pause 暫停 - + Go &offline 離線 - + Go &online 上網 - + Authentication Error 驗證錯誤 - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3211,7 +3219,7 @@ enter the displayed PIN number here: TopTracksContext - + Top Hits 流行精選 @@ -3455,27 +3463,27 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + SuperCollection 超級收藏 - + Combined libraries of all your online friends 聯合您所有線上朋友的音樂庫 - + All available albums 所有現有專輯 - + Recently Played Tracks - + Recently played tracks from all your friends From c9f287590c1431d711c56b5e920398afba555859 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 00:39:24 +0200 Subject: [PATCH 128/433] * Style fix. Sorry Leo. --- src/AccountDelegate.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AccountDelegate.cpp b/src/AccountDelegate.cpp index 7715bd003..7434fd826 100644 --- a/src/AccountDelegate.cpp +++ b/src/AccountDelegate.cpp @@ -59,7 +59,6 @@ AccountDelegate::AccountDelegate( QObject* parent ) , m_accountRowHeight( -1 ) , m_model( 0 ) { - m_defaultCover.load( RESPATH "images/sipplugin-online.png" ); m_ratingStarPositive.load( RESPATH "images/starred.png" ); m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" ); From c258f1897f674c90ad61620d6e920e6c7cecdb5c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 13:05:37 +0200 Subject: [PATCH 129/433] * Style cleanup for AvatarManager. --- src/accounts/xmpp/sip/AvatarManager.cpp | 118 +++++++++++++----------- src/accounts/xmpp/sip/AvatarManager.h | 24 ++--- 2 files changed, 75 insertions(+), 67 deletions(-) diff --git a/src/accounts/xmpp/sip/AvatarManager.cpp b/src/accounts/xmpp/sip/AvatarManager.cpp index 2c1eff6d0..9ff1d26bf 100644 --- a/src/accounts/xmpp/sip/AvatarManager.cpp +++ b/src/accounts/xmpp/sip/AvatarManager.cpp @@ -33,47 +33,51 @@ #include "utils/Logger.h" -AvatarManager::AvatarManager(Jreen::Client *client) : - m_cacheDir(TomahawkUtils::appDataDir().absolutePath().append("/jreen/")) +AvatarManager::AvatarManager( Jreen::Client* client ) + : m_cacheDir( TomahawkUtils::appDataDir().absolutePath().append( "/jreen/" ) ) { m_client = client; - m_cachedAvatars = m_cacheDir.entryList(); - connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onNewConnection())); - connect(m_client, SIGNAL(presenceReceived(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence))); - connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect( m_client, SIGNAL( serverFeaturesReceived( QSet ) ), SLOT( onNewConnection() ) ); + connect( m_client, SIGNAL( presenceReceived( Jreen::Presence ) ), SLOT( onNewPresence( Jreen::Presence ) ) ); + connect( m_client, SIGNAL( iqReceived( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); - connect(this, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); + connect( this, SIGNAL( newAvatar( QString ) ), SLOT( onNewAvatar( QString ) ) ); } + AvatarManager::~AvatarManager() { } -void AvatarManager::onNewConnection() + +void +AvatarManager::onNewConnection() { fetchVCard( m_client->jid().bare() ); } -void AvatarManager::fetchVCard(const QString &jid) +void +AvatarManager::fetchVCard( const QString& jid ) { -// qDebug() << Q_FUNC_INFO; + Jreen::IQ iq( Jreen::IQ::Get, jid ); + iq.addExtension( new Jreen::VCard() ); + Jreen::IQReply *reply = m_client->send( iq ); - Jreen::IQ iq(Jreen::IQ::Get, jid ); - iq.addExtension(new Jreen::VCard()); - Jreen::IQReply *reply = m_client->send(iq); - connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect( reply, SIGNAL( received( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); } -void AvatarManager::onNewPresence(const Jreen::Presence& presence) + +void +AvatarManager::onNewPresence( const Jreen::Presence& presence ) { Jreen::VCardUpdate::Ptr update = presence.payload(); - if(update) + if ( update ) { // qDebug() << "vcard: found update for" << presence.from().full(); - if(!isCached(update->photoHash())) + if ( !isCached( update->photoHash() ) ) { // qDebug() << presence.from().full() << "vcard: photo not cached, starting request..." << update->photoHash(); fetchVCard( presence.from().bare() ); @@ -84,78 +88,72 @@ void AvatarManager::onNewPresence(const Jreen::Presence& presence) m_JidsAvatarHashes.insert( update->photoHash(), presence.from().bare() ); if ( !this->avatar( presence.from().bare() ).isNull() ) - emit newAvatar(presence.from().bare()); + emit newAvatar( presence.from().bare() ); } } else { -// qDebug() << Q_FUNC_INFO << presence.from().full() << "got no statusupdateextension"; - //TODO: do we want this? might fetch avatars for broken clients fetchVCard( presence.from().bare() ); } } -void AvatarManager::onNewIq(const Jreen::IQ& iq) + +void +AvatarManager::onNewIq( const Jreen::IQ& iq ) { Jreen::VCard::Ptr vcard = iq.payload(); - if(vcard) + if ( vcard ) { iq.accept(); - // qDebug() << Q_FUNC_INFO << "Got vcard from " << iq.from().full(); QString id = iq.from().full(); QString avatarHash; const Jreen::VCard::Photo &photo = vcard->photo(); - if (!photo.data().isEmpty()) { + if ( !photo.data().isEmpty() ) + { // qDebug() << "vcard: got photo data" << id; - avatarHash = QCryptographicHash::hash(photo.data(), QCryptographicHash::Sha1).toHex(); + avatarHash = QCryptographicHash::hash( photo.data(), QCryptographicHash::Sha1 ).toHex(); - if (!m_cacheDir.exists()) + if ( !m_cacheDir.exists() ) m_cacheDir.mkpath( avatarDir( avatarHash ).absolutePath() ); - - QFile file(avatarPath(avatarHash)); - if (file.open(QIODevice::WriteOnly)) { - file.write(photo.data()); + QFile file( avatarPath( avatarHash ) ); + if ( file.open( QIODevice::WriteOnly ) ) + { + file.write( photo.data() ); file.close(); } - m_cachedAvatars.append(avatarHash); + m_cachedAvatars.append( avatarHash ); m_JidsAvatarHashes.insert( avatarHash, iq.from().bare() ); - Q_ASSERT(!this->avatar(iq.from().bare()).isNull()); - emit newAvatar(iq.from().bare()); - } - else - { -// qDebug() << "vcard: got no photo data" << id; + Q_ASSERT( !this->avatar( iq.from().bare() ).isNull() ); + emit newAvatar( iq.from().bare() ); } // got own presence if ( m_client->jid().bare() == id ) { -// qDebug() << Q_FUNC_INFO << "got own vcard"; - Jreen::Presence presence = m_client->presence(); Jreen::VCardUpdate::Ptr update = presence.payload(); - if (update->photoHash() != avatarHash) + if ( update->photoHash() != avatarHash ) { - qDebug() << Q_FUNC_INFO << "Updating own presence..."; - - update->setPhotoHash(avatarHash); - m_client->send(presence); + update->setPhotoHash( avatarHash ); + m_client->send( presence ); } } } } -QPixmap AvatarManager::avatar(const QString &jid) const + +QPixmap +AvatarManager::avatar( const QString& jid ) const { - if( isCached( avatarHash( jid ) ) ) + if ( isCached( avatarHash( jid ) ) ) { return QPixmap( avatarPath( avatarHash( jid ) ) ); } @@ -165,29 +163,39 @@ QPixmap AvatarManager::avatar(const QString &jid) const } } -QString AvatarManager::avatarHash(const QString &jid) const + +QString +AvatarManager::avatarHash( const QString& jid ) const { - //qDebug() << Q_FUNC_INFO << jid << m_JidsAvatarHashes.key(jid); - return m_JidsAvatarHashes.key(jid); + //qDebug() << Q_FUNC_INFO << jid << m_JidsAvatarHashes.key( jid ); + return m_JidsAvatarHashes.key( jid ); } -QDir AvatarManager::avatarDir(const QString&) const + +QDir +AvatarManager::avatarDir( const QString& /* avatarHash */ ) const { return m_cacheDir; } -QString AvatarManager::avatarPath(const QString &avatarHash) const + +QString +AvatarManager::avatarPath( const QString& avatarHash ) const { - Q_ASSERT(!avatarHash.contains("@")); - return avatarDir(avatarHash).absoluteFilePath(avatarHash); + Q_ASSERT( !avatarHash.contains( "@" ) ); + return avatarDir( avatarHash ).absoluteFilePath( avatarHash ); } -bool AvatarManager::isCached(const QString &avatarHash) const + +bool +AvatarManager::isCached( const QString& avatarHash ) const { return m_cachedAvatars.contains( avatarHash ); } -void AvatarManager::onNewAvatar(const QString&) + +void +AvatarManager::onNewAvatar( const QString& /* jid */ ) { // qDebug() << Q_FUNC_INFO << "Found new Avatar..." << jid; } diff --git a/src/accounts/xmpp/sip/AvatarManager.h b/src/accounts/xmpp/sip/AvatarManager.h index 31ab900cf..a42cee08d 100644 --- a/src/accounts/xmpp/sip/AvatarManager.h +++ b/src/accounts/xmpp/sip/AvatarManager.h @@ -32,32 +32,32 @@ class ACCOUNTDLLEXPORT AvatarManager : public QObject Q_OBJECT public: - AvatarManager(Jreen::Client *client); + AvatarManager(Jreen::Client* client); virtual ~AvatarManager(); - QPixmap avatar(const QString &jid) const; + QPixmap avatar(const QString& jid) const; signals: - void newAvatar( const QString &jid ); + void newAvatar( const QString& jid ); private slots: void onNewPresence( const Jreen::Presence& presence ); - void onNewIq(const Jreen::IQ &iq); + void onNewIq(const Jreen::IQ& iq); void onNewConnection(); - void onNewAvatar( const QString &jid ); + void onNewAvatar( const QString& jid ); private: - void fetchVCard( const QString &jid); - QString avatarHash(const QString &jid) const; - QString avatarPath(const QString &avatarHash) const; + void fetchVCard( const QString& jid ); + QString avatarHash( const QString& jid ) const; + QString avatarPath( const QString& avatarHash ) const; - QDir avatarDir(const QString &avatarHash) const; - bool isCached(const QString &avatarHash) const; + QDir avatarDir( const QString& avatarHash ) const; + bool isCached( const QString& avatarHash ) const; - Jreen::Client *m_client; + Jreen::Client* m_client; QStringList m_cachedAvatars; QDir m_cacheDir; - QMap m_JidsAvatarHashes; + QMap< QString, QString > m_JidsAvatarHashes; }; #endif // AVATARMANAGER_H From 40051b82cb9b99f89715a8359fccddad499d0ab1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 13:05:45 +0200 Subject: [PATCH 130/433] * Style cleanup for XmppSip. --- src/accounts/xmpp/sip/XmppSip.cpp | 293 ++++++++++++++---------------- src/accounts/xmpp/sip/XmppSip.h | 36 ++-- 2 files changed, 152 insertions(+), 177 deletions(-) diff --git a/src/accounts/xmpp/sip/XmppSip.cpp b/src/accounts/xmpp/sip/XmppSip.cpp index 036d1f1be..92dc69422 100644 --- a/src/accounts/xmpp/sip/XmppSip.cpp +++ b/src/accounts/xmpp/sip/XmppSip.cpp @@ -65,27 +65,32 @@ using namespace Accounts; // instead of simply copying this function for another thirdparty lib // please make it a meta-function or a macro and put it in Logger.h. kthxbbq #define JREEN_LOG_INFIX "Jreen" +#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" ) +#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" ) + + void -JreenMessageHandler(QtMsgType type, const char *msg) +JreenMessageHandler( QtMsgType type, const char *msg ) { - switch (type) + switch ( type ) { case QtDebugMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Debug: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Debug: " << msg; break; case QtWarningMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Warning: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Warning: " << msg; break; case QtCriticalMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Critical: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Critical: " << msg; break; case QtFatalMsg: - tDebug(LOGTHIRDPARTY).nospace() << JREEN_LOG_INFIX << ": " << "Fatal: " << msg; + tDebug( LOGTHIRDPARTY ).nospace() << JREEN_LOG_INFIX << ": " << "Fatal: " << msg; abort(); } } -XmppSipPlugin::XmppSipPlugin( Account *account ) + +XmppSipPlugin::XmppSipPlugin( Account* account ) : SipPlugin( account ) , m_state( Account::Disconnected ) #ifndef ENABLE_HEADLESS @@ -97,7 +102,6 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) Jreen::Logger::addHandler( JreenMessageHandler ); m_currentUsername = readUsername(); - m_currentServer = readServer(); m_currentPassword = readPassword(); m_currentPort = readPort(); @@ -122,6 +126,7 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) m_xmlConsole->show(); } #endif + // add VCardUpdate extension to own presence m_client->presence().addExtension( new Jreen::VCardUpdate() ); @@ -148,19 +153,19 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) qDebug() << "Our Port set to" << m_client->port(); // setup slots - connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onConnect())); - connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason))); - connect(m_client, SIGNAL(messageReceived(Jreen::Message)), SLOT(onNewMessage(Jreen::Message))); + connect( m_client, SIGNAL( serverFeaturesReceived( QSet ) ), SLOT( onConnect() ) ); + connect( m_client, SIGNAL( disconnected( Jreen::Client::DisconnectReason ) ), SLOT( onDisconnect( Jreen::Client::DisconnectReason ) ) ); + connect( m_client, SIGNAL( messageReceived( Jreen::Message ) ), SLOT( onNewMessage( Jreen::Message ) ) ); - connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect( m_client, SIGNAL( iqReceived( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); - connect(m_roster, SIGNAL(presenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)), - SLOT(onPresenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence))); - connect(m_roster, SIGNAL(subscriptionReceived(Jreen::RosterItem::Ptr,Jreen::Presence)), - SLOT(onSubscriptionReceived(Jreen::RosterItem::Ptr,Jreen::Presence))); + connect( m_roster, SIGNAL( presenceReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ), + SLOT( onPresenceReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ) ); + connect( m_roster, SIGNAL( subscriptionReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ), + SLOT( onSubscriptionReceived( Jreen::RosterItem::Ptr, Jreen::Presence ) ) ); #ifndef ENABLE_HEADLESS - connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); + connect( m_avatarManager, SIGNAL( newAvatar( QString ) ), SLOT( onNewAvatar( QString ) ) ); #endif m_pubSubManager = new Jreen::PubSub::Manager( m_client ); @@ -168,15 +173,16 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) // Clear status Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); - + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); } + XmppSipPlugin::~XmppSipPlugin() { //Note: the next two lines don't currently work, because the deletion wipes out internally posted events, need to talk to euro about a fix Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); + delete m_pubSubManager; delete m_avatarManager; delete m_roster; @@ -205,21 +211,20 @@ XmppSipPlugin::menu() } #endif + void XmppSipPlugin::connectPlugin() { - qDebug() << Q_FUNC_INFO; - - if( m_client->isConnected() ) + if ( m_client->isConnected() ) { qDebug() << Q_FUNC_INFO << "Already connected to server, not connecting again..."; return; } - if( m_account->configuration().contains("enforcesecure") && m_account->configuration().value("enforcesecure").toBool() ) + if ( m_account->configuration().contains( "enforcesecure" ) && m_account->configuration().value( "enforcesecure" ).toBool() ) { tLog() << Q_FUNC_INFO << "Enforcing secure connection..."; - m_client->setFeatureConfig(Jreen::Client::Encryption, Jreen::Client::Force); + m_client->setFeatureConfig( Jreen::Client::Encryption, Jreen::Client::Force ); } tDebug() << "Connecting to the Xmpp server..." << m_client->jid().full(); @@ -228,18 +233,17 @@ XmppSipPlugin::connectPlugin() QTimer::singleShot( 1000, m_client, SLOT( connectToServer() ) ); if ( m_client->connection() ) - connect(m_client->connection(), SIGNAL(error(Jreen::Connection::SocketError)), SLOT(onError(Jreen::Connection::SocketError))); + connect( m_client->connection(), SIGNAL( error( Jreen::Connection::SocketError ) ), SLOT( onError( Jreen::Connection::SocketError ) ) ); m_state = Account::Connecting; emit stateChanged( m_state ); - return; } void XmppSipPlugin::disconnectPlugin() { - if (!m_client->isConnected()) + if ( !m_client->isConnected() ) { if ( m_state != Account::Disconnected ) // might be Connecting { @@ -267,8 +271,6 @@ XmppSipPlugin::disconnectPlugin() void XmppSipPlugin::onConnect() { -// qDebug() << Q_FUNC_INFO; - // update jid resource, servers like gtalk use resource binding and may // have changed our requested /resource if ( m_client->jid().resource() != m_currentResource ) @@ -277,15 +279,9 @@ XmppSipPlugin::onConnect() emit jidChanged( m_client->jid().full() ); } - qDebug() << "Connected to xmpp as:" << m_client->jid().full(); - // set presence to least valid value - m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127); - - // set ping timeout to 15 secs (TODO: verify if this works) - m_client->setPingInterval(1000); - - // load roster + m_client->setPresence( Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127 ); + m_client->setPingInterval( 1000 ); m_roster->load(); // load XmppInfoPlugin @@ -298,7 +294,7 @@ XmppSipPlugin::onConnect() //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P // join MUC with bare jid as nickname //TODO: make the room a list of rooms and make that configurable - QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) ); + // QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) ); //m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) ); //m_room->setHistorySeconds(0); //m_room->join(); @@ -317,8 +313,6 @@ XmppSipPlugin::onConnect() void XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) { - qDebug() << Q_FUNC_INFO; - switch( reason ) { case Jreen::Client::User: @@ -345,7 +339,7 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) default: qDebug() << "Not all Client::DisconnectReasons checked" << ( int ) reason; - Q_ASSERT(false); + Q_ASSERT( false s); break; } m_state = Account::Disconnected; @@ -353,9 +347,9 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) removeMenuHelper(); - Q_FOREACH(const Jreen::JID &peer, m_peers.keys()) + Q_FOREACH( const Jreen::JID &peer, m_peers.keys() ) { - handlePeerStatus(peer, Jreen::Presence::Unavailable); + handlePeerStatus( peer, Jreen::Presence::Unavailable ); } if ( !m_infoPlugin.isNull() ) @@ -376,56 +370,51 @@ XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason ) switch( reason ) { case Jreen::Client::User: - return tr("User Interaction"); + return tr( "User Interaction" ); break; case Jreen::Client::HostUnknown: - return tr("Host is unknown"); + return tr( "Host is unknown" ); break; case Jreen::Client::ItemNotFound: - return tr("Item not found"); + return tr( "Item not found" ); break; case Jreen::Client::AuthorizationError: - return tr("Authorization Error"); + return tr( "Authorization Error" ); break; case Jreen::Client::RemoteStreamError: - return tr("Remote Stream Error"); + return tr( "Remote Stream Error" ); break; case Jreen::Client::RemoteConnectionFailed: - return tr("Remote Connection failed"); + return tr( "Remote Connection failed" ); break; case Jreen::Client::InternalServerError: - return tr("Internal Server Error"); + return tr( "Internal Server Error" ); break; case Jreen::Client::SystemShutdown: - return tr("System shutdown"); + return tr( "System shutdown" ); break; case Jreen::Client::Conflict: - return tr("Conflict"); + return tr( "Conflict" ); break; - - case Jreen::Client::Unknown: - return tr("Unknown"); - break; - case Jreen::Client::NoCompressionSupport: - return tr("No Compression Support"); + return tr( "No Compression Support" ); break; - case Jreen::Client::NoEncryptionSupport: - return tr("No Encryption Support"); + return tr( "No Encryption Support" ); break; - case Jreen::Client::NoAuthorizationSupport: - return tr("No Authorization Support"); + return tr( "No Authorization Support" ); break; - case Jreen::Client::NoSupportedFeature: - return tr("No Supported Feature"); + return tr( "No Supported Feature" ); + break; + case Jreen::Client::Unknown: + return tr( "Unknown" ); break; default: qDebug() << "Not all Client::DisconnectReasons checked"; - Q_ASSERT(false); + Q_ASSERT( false ); break; } @@ -441,9 +430,8 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg ) { qDebug() << Q_FUNC_INFO << to << msg; - if ( !m_client ) { + if ( !m_client ) return; - } /******************************************************* * Obsolete this by a SipMessage class @@ -451,29 +439,24 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg ) QJson::Parser parser; bool ok; QVariant v = parser.parse( msg.toAscii(), &ok ); - if ( !ok || v.type() != QVariant::Map ) + if ( !ok || v.type() != QVariant::Map ) { qDebug() << "Invalid JSON in Xmpp msg"; return; } + QVariantMap m = v.toMap(); /*******************************************************/ TomahawkXmppMessage *sipMessage; - if(m["visible"].toBool()) + if ( m["visible"].toBool() ) { - sipMessage = new TomahawkXmppMessage( m["ip"].toString(), - m["port"].toInt(), - m["uniqname"].toString(), - m["key"].toString() - ); + sipMessage = new TomahawkXmppMessage( m["ip"].toString(), m["port"].toInt(), m["uniqname"].toString(), m["key"].toString() ); } else - { sipMessage = new TomahawkXmppMessage(); - } - qDebug() << "Send sip messsage to " << to; + qDebug() << "Send sip messsage to" << to; Jreen::IQ iq( Jreen::IQ::Set, to ); iq.addExtension( sipMessage ); Jreen::IQReply *reply = m_client->send( iq ); @@ -485,12 +468,10 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg ) void XmppSipPlugin::broadcastMsg( const QString& msg ) { - qDebug() << Q_FUNC_INFO; - if ( !m_client ) return; - foreach( const Jreen::JID& jid, m_peers.keys() ) + foreach ( const Jreen::JID& jid, m_peers.keys() ) { sendMsg( jid.full(), msg ); } @@ -501,14 +482,11 @@ void XmppSipPlugin::addContact( const QString& jid, const QString& msg ) { // Add contact to the Tomahawk group on the roster - QString realJid = jid; - if( !realJid.contains( '@' ) ) + if ( !realJid.contains( '@' ) ) realJid += defaultSuffix(); m_roster->subscribe( realJid, msg, realJid, QStringList() << "Tomahawk" ); - - return; } @@ -532,24 +510,24 @@ XmppSipPlugin::showAddFriendDialog() void XmppSipPlugin::publishTune( const QUrl& url, const InfoSystem::InfoStringHash& trackInfo ) { - if( m_account->configuration().value("publishtracks").toBool() == false ) + if ( m_account->configuration().value("publishtracks").toBool() == false ) { - tDebug() << Q_FUNC_INFO << m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; + tDebug() << Q_FUNC_INFO << m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; return; } if ( trackInfo.isEmpty() ) { Jreen::Tune::Ptr tune( new Jreen::Tune() ); - m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); } Jreen::Tune::Ptr tune( new Jreen::Tune() ); tune->setTitle( trackInfo.value( "title" ) ); tune->setArtist( trackInfo.value( "artist" ) ); - tune->setLength( trackInfo.value("duration").toInt() ); - tune->setTrack( trackInfo.value("albumpos") ); + tune->setLength( trackInfo.value( "duration" ).toInt() ); + tune->setTrack( trackInfo.value( "albumpos" ) ); //TODO: provide a rating once available in Tomahawk tune->setRating( 10 ); @@ -558,7 +536,7 @@ XmppSipPlugin::publishTune( const QUrl& url, const InfoSystem::InfoStringHash& t tune->setSource( "Tomahawk" ); tune->setUri( url ); - tDebug() << Q_FUNC_INFO << "Setting URI of " << tune->uri().toString(); + tDebug() << Q_FUNC_INFO << "Setting URI of" << tune->uri().toString(); m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); } @@ -642,13 +620,15 @@ XmppSipPlugin::configurationChanged() } } -void XmppSipPlugin::setupClientHelper() + +void +XmppSipPlugin::setupClientHelper() { Jreen::JID jid = Jreen::JID( m_currentUsername ); m_client->setJID( jid ); m_client->setPassword( m_currentPassword ); - if( !m_currentServer.isEmpty() ) + if ( !m_currentServer.isEmpty() ) { // set explicit server details m_client->setServer( m_currentServer ); @@ -662,20 +642,22 @@ void XmppSipPlugin::setupClientHelper() } } -void XmppSipPlugin::addMenuHelper() + +void +XmppSipPlugin::addMenuHelper() { #ifndef ENABLE_HEADLESS - if( !m_menu ) + if ( !m_menu ) { m_menu = new QMenu( QString( "%1 (" ).arg( friendlyName() ).append( readUsername() ).append(")" ) ); QAction* addFriendAction = m_menu->addAction( tr( "Add Friend..." ) ); - connect( addFriendAction, SIGNAL( triggered() ), this, SLOT( showAddFriendDialog() ) ); + connect( addFriendAction, SIGNAL( triggered() ), SLOT( showAddFriendDialog() ) ); - if( readXmlConsoleEnabled() ) + if ( readXmlConsoleEnabled() ) { - QAction* showXmlConsoleAction = m_menu->addAction( tr( "XML Console...") ); - connect( showXmlConsoleAction, SIGNAL( triggered() ), this, SLOT( showXmlConsole() ) ); + QAction* showXmlConsoleAction = m_menu->addAction( tr( "XML Console..." ) ); + connect( showXmlConsoleAction, SIGNAL( triggered() ), SLOT( showXmlConsole() ) ); } emit addMenu( m_menu ); @@ -683,10 +665,12 @@ void XmppSipPlugin::addMenuHelper() #endif } -void XmppSipPlugin::removeMenuHelper() + +void +XmppSipPlugin::removeMenuHelper() { #ifndef ENABLE_HEADLESS - if( m_menu ) + if ( m_menu ) { emit removeMenu( m_menu ); @@ -697,37 +681,35 @@ void XmppSipPlugin::removeMenuHelper() } -void XmppSipPlugin::onNewMessage( const Jreen::Message& message ) +void +XmppSipPlugin::onNewMessage( const Jreen::Message& message ) { if ( m_state != Account::Connected ) return; -// qDebug() << Q_FUNC_INFO << "message type" << message.subtype(); - QString from = message.from().full(); QString msg = message.body(); - if(msg.isEmpty()) + if ( msg.isEmpty() ) return; - if( message.subtype() == Jreen::Message::Error ) + if ( message.subtype() == Jreen::Message::Error ) { - tDebug() << Q_FUNC_INFO << "Received error message from " << from << ", not answering... (Condition: " + tDebug() << Q_FUNC_INFO << "Received error message from" << from << ", not answering... (Condition:" << ( message.error().isNull() ? -1 : message.error()->condition() ) << ")"; return; } SipInfo info = SipInfo::fromJson( msg ); - if ( !info.isValid() ) { QString to = from; - QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player" - " (http://gettomahawk.com). If you are getting this message, the person you" - " are trying to reach is probably not signed on, so please try again later!") ); + QString response = QString( tr( "I'm sorry -- I'm just an automatic presence used by Tomahawk Player" + " (http://gettomahawk.com). If you are getting this message, the person you" + " are trying to reach is probably not signed on, so please try again later!" ) ); // this is not a sip message, so we send it directly through the client - m_client->send( Jreen::Message ( Jreen::Message::Error, Jreen::JID(to), response) ); + m_client->send( Jreen::Message ( Jreen::Message::Error, Jreen::JID( to ), response) ); emit msgReceived( from, msg ); return; @@ -738,7 +720,8 @@ void XmppSipPlugin::onNewMessage( const Jreen::Message& message ) } -void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence ) +void +XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ) { Q_UNUSED(item); if ( m_state != Account::Connected ) @@ -749,19 +732,20 @@ void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, cons qDebug() << Q_FUNC_INFO << "* New presence:" << fulljid << presence.subtype(); - if( jid == m_client->jid() ) + if ( jid == m_client->jid() ) return; - if ( presence.error() ) { + if ( presence.error() ) + { //qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error"; return; } // ignore anyone not Running tomahawk: Jreen::Capabilities::Ptr caps = presence.payload(); - if( caps ) + if ( caps ) { - qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node() << "requesting disco..."; + qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps" << caps->node() << "requesting disco..."; // request disco features QString node = caps->node() + '#' + caps->ver(); @@ -773,7 +757,7 @@ void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, cons reply->setData( RequestDisco ); connect( reply, SIGNAL( received( Jreen::IQ ) ), SLOT( onNewIq( Jreen::IQ ) ) ); } - else if( !caps ) + else if ( !caps ) { // qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps"; if ( presenceMeansOnline( m_peers[ jid ] ) ) @@ -782,46 +766,40 @@ void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, cons } -void XmppSipPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ) +void +XmppSipPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ) { if ( m_state != Account::Connected ) return; -// qDebug() << Q_FUNC_INFO << "presence type:" << presence.subtype(); - if(item) + if ( item ) qDebug() << Q_FUNC_INFO << presence.from().full() << "subs" << item->subscription() << "ask" << item->ask(); else qDebug() << Q_FUNC_INFO << "item empty"; // don't do anything if the contact is already subscribed to us - if( presence.subtype() != Jreen::Presence::Subscribe || - ( - item && (item->subscription() == Jreen::RosterItem::From || item->subscription() == Jreen::RosterItem::Both) - ) - ) + if ( presence.subtype() != Jreen::Presence::Subscribe || + ( item && (item->subscription() == Jreen::RosterItem::From || item->subscription() == Jreen::RosterItem::Both ) ) ) { return; } // check if the requester is already on the roster - if(item && - ( - item->subscription() == Jreen::RosterItem::To || - ( item->subscription() == Jreen::RosterItem::None && !item->ask().isEmpty() ) - ) - ) + if ( item && + ( item->subscription() == Jreen::RosterItem::To || ( item->subscription() == Jreen::RosterItem::None && !item->ask().isEmpty() ) ) ) { qDebug() << Q_FUNC_INFO << presence.from().bare() << "already on the roster so we assume ack'ing subscription request is okay..."; - m_roster->allowSubscription(presence.from(), true); + m_roster->allowSubscription( presence.from(), true ); return; } + #ifndef ENABLE_HEADLESS // preparing the confirm box for the user QMessageBox *confirmBox = new QMessageBox( QMessageBox::Question, tr( "Authorize User" ), - QString( tr( "Do you want to grant %1 access to your Collection?" ) ).arg(presence.from().bare()), + QString( tr( "Do you want to grant %1 access to your Collection?" ) ).arg( presence.from().bare() ), QMessageBox::Yes | QMessageBox::No, TomahawkUtils::tomahawkWindow() ); @@ -857,11 +835,10 @@ XmppSipPlugin::onSubscriptionRequestConfirmed( int result ) sender()->deleteLater(); QMessageBox::StandardButton allowSubscription = static_cast< QMessageBox::StandardButton >( result ); - if ( allowSubscription == QMessageBox::Yes ) { qDebug() << Q_FUNC_INFO << jid.bare() << "accepted by user, adding to roster"; - addContact(jid, ""); + addContact( jid, "" ); } else { @@ -873,7 +850,8 @@ XmppSipPlugin::onSubscriptionRequestConfirmed( int result ) } -void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) +void +XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) { if ( m_state != Account::Connected ) return; @@ -887,10 +865,9 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) Jreen::Disco::Info *discoInfo = iq.payload< Jreen::Disco::Info >().data(); if ( !discoInfo ) return; + iq.accept(); - Jreen::JID jid = iq.from(); - Jreen::DataForm::Ptr form = discoInfo->form(); if ( discoInfo->features().contains( TOMAHAWK_FEATURE ) ) @@ -906,8 +883,8 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload(); if ( softwareVersion ) { - QString versionString = QString("%1 %2 %3").arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() ); - qDebug() << Q_FUNC_INFO << "Received software version for " << iq.from().full() << ":" << versionString; + QString versionString = QString( "%1 %2 %3" ).arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() ); + qDebug() << Q_FUNC_INFO << "Received software version for" << iq.from().full() << ":" << versionString; emit softwareVersionReceived( iq.from().full(), versionString ); } } @@ -935,9 +912,8 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) SipInfo info; info.setVisible( sipMessage->visible() ); - if( sipMessage->visible() ) + if ( sipMessage->visible() ) { - QHostInfo hi; hi.setHostName( sipMessage->ip() ); info.setHost( hi ); @@ -955,7 +931,8 @@ void XmppSipPlugin::onNewIq( const Jreen::IQ& iq ) } -bool XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p ) +bool +XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p ) { switch( p ) { @@ -964,22 +941,21 @@ bool XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p ) case Jreen::Presence::Error: return false; break; + default: return true; } } -void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ) +void +XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ) { QString fulljid = jid.full(); // "going offline" event if ( !presenceMeansOnline( presenceType ) && - ( !m_peers.contains( jid ) || - presenceMeansOnline( m_peers.value( jid ) ) - ) - ) + ( !m_peers.contains( jid ) || presenceMeansOnline( m_peers.value( jid ) ) ) ) { m_peers[ jid ] = presenceType; qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid; @@ -990,10 +966,7 @@ void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Ty // "coming online" event if ( presenceMeansOnline( presenceType ) && - ( !m_peers.contains( jid ) || - !presenceMeansOnline( m_peers.value( jid ) ) - ) - ) + ( !m_peers.contains( jid ) || !presenceMeansOnline( m_peers.value( jid ) ) ) ) { m_peers[ jid ] = presenceType; qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid; @@ -1020,7 +993,8 @@ void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Ty } -void XmppSipPlugin::onNewAvatar( const QString& jid ) +void +XmppSipPlugin::onNewAvatar( const QString& jid ) { #ifndef ENABLE_HEADLESS // qDebug() << Q_FUNC_INFO << jid; @@ -1031,20 +1005,20 @@ void XmppSipPlugin::onNewAvatar( const QString& jid ) // find peers for the jid QList< Jreen::JID > peers = m_peers.keys(); - foreach ( const Jreen::JID &peer, peers ) + foreach ( const Jreen::JID& peer, peers ) { - if( peer.bare() == jid ) + if ( peer.bare() == jid ) { - emit avatarReceived ( peer.full(), m_avatarManager->avatar( jid ) ); + emit avatarReceived( peer.full(), m_avatarManager->avatar( jid ) ); } } if ( jid == m_client->jid().bare() ) // own avatar - emit avatarReceived ( m_avatarManager->avatar( jid ) ); + emit avatarReceived( m_avatarManager->avatar( jid ) ); else // someone else's avatar - emit avatarReceived ( jid, m_avatarManager->avatar( jid ) ); + emit avatarReceived( jid, m_avatarManager->avatar( jid ) ); #endif } @@ -1065,6 +1039,7 @@ XmppSipPlugin::readUsername() return credentials.contains( "username" ) ? credentials[ "username" ].toString() : QString(); } + QString XmppSipPlugin::readPassword() { diff --git a/src/accounts/xmpp/sip/XmppSip.h b/src/accounts/xmpp/sip/XmppSip.h index ce95a9615..de9f09282 100644 --- a/src/accounts/xmpp/sip/XmppSip.h +++ b/src/accounts/xmpp/sip/XmppSip.h @@ -48,9 +48,6 @@ #include #endif -#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" ) -#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" ) - #include "accounts/AccountDllMacro.h" #include "../XmppInfoPlugin.h" @@ -90,10 +87,11 @@ public slots: virtual void checkSettings(); virtual void configurationChanged(); virtual void sendMsg( const QString& to, const QString& msg ); - void broadcastMsg( const QString &msg ); - virtual void addContact( const QString &jid, const QString& msg = QString() ); + virtual void addContact( const QString& jid, const QString& msg = QString() ); + + void broadcastMsg( const QString& msg ); void showAddFriendDialog(); - void publishTune( const QUrl &url, const Tomahawk::InfoSystem::InfoStringHash &trackInfo ); + void publishTune( const QUrl& url, const Tomahawk::InfoSystem::InfoStringHash& trackInfo ); protected: virtual QString defaultSuffix() const; @@ -103,14 +101,14 @@ private slots: void onConnect(); void onDisconnect( Jreen::Client::DisconnectReason reason ); - void onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence ); - void onSubscriptionReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence ); + void onPresenceReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ); + void onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence ); void onSubscriptionRequestConfirmed( int result ); void onNewMessage( const Jreen::Message& message ); void onError( const Jreen::Connection::SocketError& e ); - void onNewIq( const Jreen::IQ &iq ); - void onNewAvatar( const QString &jid ); + void onNewIq( const Jreen::IQ& iq ); + void onNewAvatar( const QString& jid ); private: bool readXmlConsoleEnabled(); @@ -125,7 +123,7 @@ private: void removeMenuHelper(); bool presenceMeansOnline( Jreen::Presence::Type p ); - void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType ); + void handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ); QString m_currentUsername; QString m_currentPassword; @@ -133,22 +131,24 @@ private: int m_currentPort; QString m_currentResource; - QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin> m_infoPlugin; + QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin > m_infoPlugin; Tomahawk::Accounts::Account::ConnectionState m_state; // sort out - Jreen::Client *m_client; + Jreen::Client* m_client; + + Jreen::MUCRoom* m_room; + Jreen::SimpleRoster* m_roster; + QHash< Jreen::JID, Jreen::Presence::Type > m_peers; - Jreen::MUCRoom *m_room; - Jreen::SimpleRoster *m_roster; - QHash m_peers; #ifndef ENABLE_HEADLESS - QHash m_subscriptionConfirmBoxes; + QHash< Jreen::JID, QMessageBox* > m_subscriptionConfirmBoxes; QMenu* m_menu; XmlConsole* m_xmlConsole; #endif + enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard, RequestVersion, RequestedVersion }; - AvatarManager *m_avatarManager; + AvatarManager* m_avatarManager; Jreen::PubSub::Manager* m_pubSubManager; }; From e9aaf56b3d9ed9a2eb1b7759dcd9172b974bdfcb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 13:16:25 +0200 Subject: [PATCH 131/433] * Fixed accidental typo. --- src/accounts/xmpp/sip/XmppSip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/accounts/xmpp/sip/XmppSip.cpp b/src/accounts/xmpp/sip/XmppSip.cpp index 92dc69422..2c202f589 100644 --- a/src/accounts/xmpp/sip/XmppSip.cpp +++ b/src/accounts/xmpp/sip/XmppSip.cpp @@ -339,7 +339,7 @@ XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) default: qDebug() << "Not all Client::DisconnectReasons checked" << ( int ) reason; - Q_ASSERT( false s); + Q_ASSERT( false ); break; } m_state = Account::Disconnected; From be52d8124813cc20e35baee4985d3e963a955c64 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 13:22:25 +0200 Subject: [PATCH 132/433] * Fixed TWK-842: Use sheet dialog when asking for new station's name. --- src/TomahawkWindow.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 9ef331c0a..a2856014c 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -720,7 +720,7 @@ void TomahawkWindow::createStation() { bool ok; - QString name = QInputDialog::getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, tr( "New Station" ), &ok ); + QString name = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, tr( "New Station" ), &ok ); if ( !ok || name.isEmpty() ) return; @@ -739,11 +739,12 @@ void TomahawkWindow::createPlaylist() { PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet ); + #ifndef Q_OS_MAC playlistSelectorDlg->setModal( true ); #endif - connect( playlistSelectorDlg, SIGNAL( finished( int ) ), this, SLOT( playlistCreateDialogFinished( int ) ) ); + connect( playlistSelectorDlg, SIGNAL( finished( int ) ), SLOT( playlistCreateDialogFinished( int ) ) ); playlistSelectorDlg->show(); } @@ -758,14 +759,17 @@ TomahawkWindow::playlistCreateDialogFinished( int ret ) if ( playlistName.isEmpty() ) playlistName = tr( "New Playlist" ); - if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) { - + if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) + { playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() ); ViewManager::instance()->show( playlist ); - } else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) { + } + else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) + { // create Auto Playlist createAutomaticPlaylist( playlistName ); } + playlistSelectorDlg->deleteLater(); } From 684f33a99ff3aafafa514a7b1667c202e7cb83c8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 14:17:53 +0200 Subject: [PATCH 133/433] * Removed obsolete signal connections in RelatedArtistsContext. --- src/libtomahawk/context/pages/RelatedArtistsContext.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp index 41ab75a2f..8d58719a0 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp @@ -47,12 +47,6 @@ RelatedArtistsContext::RelatedArtistsContext() m_proxy = new QGraphicsProxyWidget(); m_proxy->setWidget( m_relatedView ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); } From bea23d7dbed87366828a0c441ea2e97d0f94b742 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 14:18:51 +0200 Subject: [PATCH 134/433] * Don't emit selection requests if we didn't activate a ViewPage. --- src/sourcetree/SourcesModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcetree/SourcesModel.cpp b/src/sourcetree/SourcesModel.cpp index e0934a368..3a56eded8 100644 --- a/src/sourcetree/SourcesModel.cpp +++ b/src/sourcetree/SourcesModel.cpp @@ -549,7 +549,7 @@ SourcesModel::linkSourceItemToPage( SourceTreeItem* item, ViewPage* p ) // TODO handle removal m_sourceTreeLinks[ p ] = item; - if( m_viewPageDelayedCacheItem == p ) + if ( p && m_viewPageDelayedCacheItem == p ) emit selectRequest( QPersistentModelIndex( indexFromItem( item ) ) ); if ( QObject* obj = dynamic_cast< QObject* >( p ) ) From 9d26f342d387955d43a776d5f5a28e9decca79cb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 14:19:33 +0200 Subject: [PATCH 135/433] * Always select the current view-page in the SourceTreeView. --- src/sourcetree/SourceTreeView.cpp | 41 ++++++++++++++++++++----------- src/sourcetree/SourceTreeView.h | 3 +++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index 0e57b8d65..c45a66d87 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -111,7 +111,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) header()->setResizeMode( 0, QHeaderView::Stretch ); connect( this, SIGNAL( expanded( QModelIndex ) ), SLOT( onItemExpanded( QModelIndex ) ) ); -// connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), SLOT( onSelectionChanged() ) ); + connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), SLOT( onSelectionChanged() ) ); showOfflineSources( TomahawkSettings::instance()->showOfflineSources() ); @@ -245,6 +245,18 @@ SourceTreeView::showOfflineSources( bool offlineSourcesShown ) } +void +SourceTreeView::onSelectionChanged() +{ + if ( currentIndex() != m_selectedIndex ) + { + selectionModel()->blockSignals( true ); + selectionModel()->select( m_selectedIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current ); + selectionModel()->blockSignals( false ); + } +} + + void SourceTreeView::onItemActivated( const QModelIndex& index ) { @@ -271,7 +283,7 @@ void SourceTreeView::onItemExpanded( const QModelIndex& idx ) { // make sure to expand children nodes for collections - if( idx.data( SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Collection ) + if ( idx.data( SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Collection ) { for( int i = 0; i < model()->rowCount( idx ); i++ ) { @@ -284,6 +296,8 @@ SourceTreeView::onItemExpanded( const QModelIndex& idx ) void SourceTreeView::selectRequest( const QPersistentModelIndex& idx ) { + m_selectedIndex = idx; + if ( !selectionModel()->selectedIndexes().contains( idx ) ) { scrollTo( idx, QTreeView::EnsureVisible ); @@ -357,7 +371,7 @@ SourceTreeView::deletePlaylist( const QModelIndex& idxIn ) playlist_ptr playlist = item->playlist(); Playlist::remove( playlist ); } - else if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + else if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) { DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( idx ); dynplaylist_ptr playlist = item->dynPlaylist(); @@ -374,7 +388,7 @@ SourceTreeView::copyPlaylistLink() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) { DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( m_contextMenuIndex ); dynplaylist_ptr playlist = item->dynPlaylist(); @@ -409,7 +423,7 @@ SourceTreeView::addToLocal() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) { DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( m_contextMenuIndex ); dynplaylist_ptr playlist = item->dynPlaylist(); @@ -442,7 +456,7 @@ SourceTreeView::latchOnOrCatchUp() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type != SourcesModel::Collection ) + if ( type != SourcesModel::Collection ) return; SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex ); @@ -461,7 +475,7 @@ SourceTreeView::latchOff() return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type != SourcesModel::Collection ) + if ( type != SourcesModel::Collection ) return; const SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex ); @@ -498,7 +512,7 @@ SourceTreeView::latchModeToggled( bool checked ) return; SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if( type != SourcesModel::Collection ) + if ( type != SourcesModel::Collection ) return; const SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex ); @@ -510,7 +524,7 @@ SourceTreeView::latchModeToggled( bool checked ) void SourceTreeView::renamePlaylist() { - if( !m_contextMenuIndex.isValid() && !selectionModel()->selectedIndexes().isEmpty() ) + if ( !m_contextMenuIndex.isValid() && !selectionModel()->selectedIndexes().isEmpty() ) edit( selectionModel()->selectedIndexes().first() ); else edit( m_contextMenuIndex ); @@ -533,7 +547,7 @@ SourceTreeView::onCustomContextMenu( const QPoint& pos ) model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Station ) { PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); - if( item->playlist()->author()->isLocal() ) + if ( item->playlist()->author()->isLocal() ) m_playlistMenu.exec( mapToGlobal( pos ) ); else m_roPlaylistMenu.exec( mapToGlobal( pos ) ); @@ -610,7 +624,7 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event ) m_dropRect = rect; SourceTreeItem* item = itemFromIndex< SourceTreeItem >( index ); - if( item->willAcceptDrag( event->mimeData() ) ) + if ( item->willAcceptDrag( event->mimeData() ) ) { accept = true; @@ -698,7 +712,7 @@ SourceTreeView::dropEvent( QDropEvent* event ) void SourceTreeView::keyPressEvent( QKeyEvent *event ) { - if( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !selectionModel()->selectedIndexes().isEmpty() ) + if ( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !selectionModel()->selectedIndexes().isEmpty() ) { QModelIndex idx = selectionModel()->selectedIndexes().first(); if ( model()->data( idx, SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::StaticPlaylist || @@ -708,9 +722,8 @@ SourceTreeView::keyPressEvent( QKeyEvent *event ) PlaylistItem* item = itemFromIndex< PlaylistItem >( idx ); Q_ASSERT( item ); - if( item->playlist()->author()->isLocal() ) { + if ( item->playlist()->author()->isLocal() ) deletePlaylist( idx ); - } } event->accept(); } diff --git a/src/sourcetree/SourceTreeView.h b/src/sourcetree/SourceTreeView.h index f9f71af47..388649d3c 100644 --- a/src/sourcetree/SourceTreeView.h +++ b/src/sourcetree/SourceTreeView.h @@ -81,6 +81,7 @@ private slots: void latchModeToggled( bool checked ); void onCustomContextMenu( const QPoint& pos ); + void onSelectionChanged(); protected: void drawRow( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -113,6 +114,8 @@ private: bool m_dragging; QRect m_dropRect; QPersistentModelIndex m_dropIndex; + + QPersistentModelIndex m_selectedIndex; }; #endif // SOURCETREEVIEW_H From 7cacc42737b5c462467a5f28c92606d6dcad827f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 16:11:57 +0200 Subject: [PATCH 136/433] * Cleaned up DropJobNotifier. --- src/libtomahawk/utils/DropJobNotifier.cpp | 33 ++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libtomahawk/utils/DropJobNotifier.cpp b/src/libtomahawk/utils/DropJobNotifier.cpp index 535c5a295..085e42a99 100644 --- a/src/libtomahawk/utils/DropJobNotifier.cpp +++ b/src/libtomahawk/utils/DropJobNotifier.cpp @@ -32,25 +32,25 @@ #include #include -class QNetworkReply; - using namespace Tomahawk; + DropJobNotifier::DropJobNotifier( QPixmap servicePixmap, QString service, DropJob::DropType type, QNetworkReply* job ) : JobStatusItem() , m_type( "unknown" ) , m_job( 0 ) - , m_pixmap ( servicePixmap ) - , m_service ( service ) + , m_pixmap( servicePixmap ) + , m_service( service ) { init( type ); - if( m_service.isEmpty() ) + if ( m_service.isEmpty() ) m_service = "DropJob"; connect( job, SIGNAL( finished() ), this, SLOT( setFinished() ) ); } + DropJobNotifier::DropJobNotifier( QPixmap pixmap, DropJob::DropType type ) : JobStatusItem() , m_job( 0 ) @@ -61,23 +61,24 @@ DropJobNotifier::DropJobNotifier( QPixmap pixmap, DropJob::DropType type ) DropJobNotifier::~DropJobNotifier() -{} +{ +} + void DropJobNotifier::init( DropJob::DropType type ) { - if( type == DropJob::Playlist ) - m_type = "playlist"; + if ( type == DropJob::Playlist ) + m_type = tr( "playlist" ); - if( type == DropJob::Artist ) - m_type = "artist"; + if ( type == DropJob::Artist ) + m_type = tr( "artist" ); - if( type == DropJob::Track ) - m_type = "track"; - - if( type == DropJob::Album ) - m_type = "album"; + if ( type == DropJob::Track ) + m_type = tr( "track" ); + if ( type == DropJob::Album ) + m_type = tr( "album" ); } @@ -87,6 +88,7 @@ DropJobNotifier::rightColumnText() const return QString(); } + QPixmap DropJobNotifier::icon() const { @@ -108,6 +110,7 @@ DropJobNotifier::mainText() const } } + void DropJobNotifier::setFinished() { From 0980044ef6122944d54b6dd9b0970b7be9c66b1a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 16:12:28 +0200 Subject: [PATCH 137/433] * Style fix for JobStatusModel. --- src/libtomahawk/jobview/JobStatusModel.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/jobview/JobStatusModel.cpp b/src/libtomahawk/jobview/JobStatusModel.cpp index 8be72d328..e3ec86e9a 100644 --- a/src/libtomahawk/jobview/JobStatusModel.cpp +++ b/src/libtomahawk/jobview/JobStatusModel.cpp @@ -24,10 +24,10 @@ #include + JobStatusModel::JobStatusModel( QObject* parent ) : QAbstractListModel ( parent ) { - } @@ -52,10 +52,9 @@ JobStatusModel::addJob( JobStatusItem* item ) currentJobCount++; m_jobTypeCount[ item->type() ] = currentJobCount; } - - - connect( item, SIGNAL( statusChanged() ), this, SLOT( itemUpdated() ) ); - connect( item, SIGNAL( finished() ), this, SLOT( itemFinished() ) ); + + connect( item, SIGNAL( statusChanged() ), SLOT( itemUpdated() ) ); + connect( item, SIGNAL( finished() ), SLOT( itemFinished() ) ); if ( item->collapseItem() ) { @@ -77,6 +76,7 @@ JobStatusModel::addJob( JobStatusItem* item ) beginInsertRows( QModelIndex(), currentEndRow, currentEndRow ); m_items.append( item ); endInsertRows(); + if ( item->hasCustomDelegate() ) { tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "job has custom delegate"; @@ -228,5 +228,4 @@ JobStatusModel::itemUpdated() const QModelIndex idx = index( m_items.indexOf( item ), 0, QModelIndex() ); emit dataChanged( idx, idx ); - return; } From c8afb7a7c61fcbb7510cfe97eafc57f6cf1d4744 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 16:12:51 +0200 Subject: [PATCH 138/433] * DropJob now uses the new API. --- src/libtomahawk/DropJob.cpp | 195 ++++++------------------------------ src/libtomahawk/DropJob.h | 13 +-- 2 files changed, 36 insertions(+), 172 deletions(-) diff --git a/src/libtomahawk/DropJob.cpp b/src/libtomahawk/DropJob.cpp index 029eb44cb..674a8840d 100644 --- a/src/libtomahawk/DropJob.cpp +++ b/src/libtomahawk/DropJob.cpp @@ -32,7 +32,6 @@ #include "utils/Logger.h" #include "utils/TomahawkUtils.h" #include "GlobalActionManager.h" -#include "infosystem/InfoSystem.h" #include "utils/XspfLoader.h" #include "jobview/JobStatusView.h" #include "jobview/JobStatusModel.h" @@ -57,7 +56,6 @@ DropJob::DropJob( QObject *parent ) , m_getWholeAlbums( false ) , m_top10( false ) , m_dropAction( Default ) - , m_dropJob( 0 ) { } @@ -294,11 +292,11 @@ DropJob::tracksFromQueryList( const QMimeData* data ) query_ptr* query = reinterpret_cast(qptr); if ( query && !query->isNull() ) { - tDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track(); + tDebug() << "Dropped query item:" << query->data()->toString(); if ( m_top10 ) { - getTopTen( query->data()->artist() ); + queries << getTopTen( query->data()->artist() ); } else if ( m_getWholeArtists ) { @@ -376,7 +374,7 @@ DropJob::tracksFromAlbumMetaData( const QMimeData *data ) stream >> album; if ( m_top10 ) - getTopTen( artist ); + queries << getTopTen( artist ); else if ( m_getWholeArtists ) queries << getArtist( artist ); else @@ -405,7 +403,7 @@ DropJob::tracksFromArtistMetaData( const QMimeData *data ) } else { - getTopTen( artist ); + queries << getTopTen( artist ); } } return queries; @@ -569,6 +567,7 @@ DropJob::handleRdioUrls( const QString& urlsRaw ) rdio->parse( urls ); } + void DropJob::handleGroovesharkUrls ( const QString& urlsRaw ) { @@ -594,7 +593,6 @@ DropJob::handleGroovesharkUrls ( const QString& urlsRaw ) } - void DropJob::handleAllUrls( const QString& urls ) { @@ -672,22 +670,28 @@ DropJob::expandedUrls( QStringList urls ) void DropJob::onTracksAdded( const QList& tracksList ) { - qDebug() << Q_FUNC_INFO; - if ( m_dropJob ) + tDebug() << Q_FUNC_INFO << tracksList.count(); + +/* if ( results.isEmpty() ) { - m_dropJob->setFinished(); - m_dropJob = 0; + const QString which = album.isEmpty() ? "artist" : "album"; + JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "No tracks found for given %1" ).arg( which ), 5 ) ); + }*/ + + if ( !m_dropJob.isEmpty() ) + { + m_dropJob.takeFirst()->setFinished(); } m_resultList.append( tracksList ); if ( --m_queryCount == 0 ) { - if ( m_onlyLocal ) +/* if ( m_onlyLocal ) removeRemoteSources(); if ( !m_allowDuplicates ) - removeDuplicates(); + removeDuplicates();*/ emit tracks( m_resultList ); deleteLater(); @@ -695,67 +699,6 @@ DropJob::onTracksAdded( const QList& tracksList ) } -void -DropJob::tracksFromDB( const QList< query_ptr >& tracks ) -{ - // Tracks that we get from databasecommand_alltracks are resolved only against the database and explicitly marked - // as finished. if the source they resolve to is offline they will not resolve against any resolver. - // explicitly resolve them if they fall in that case first - foreach( const query_ptr& track, tracks ) - { - if ( !track->playable() && !track->solved() && track->results().size() ) // we have offline results - { - track->setResolveFinished( false ); - Pipeline::instance()->resolve( track ); - } - } - - album_ptr albumPtr; - artist_ptr artistPtr; - if ( Tomahawk::Album* album = qobject_cast< Tomahawk::Album* >( sender() ) ) - { - foreach ( const album_ptr& ptr, m_albumsToKeep ) - if ( ptr.data() == album ) - { - albumPtr = ptr; - m_albumsToKeep.remove( ptr ); - } - } - else if ( Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() ) ) - { - foreach ( const artist_ptr& ptr, m_artistsToKeep ) - if ( ptr.data() == artist ) - { - artistPtr = ptr; - m_artistsToKeep.remove( ptr ); - } - } - - // If we have no tracks, this means no sources in our network have the give request (artist or album) - // Since we really do want to try to drop them, we ask the infosystem as well. - if ( tracks.isEmpty() ) - { - if ( !albumPtr.isNull() && !albumPtr->artist().isNull() ) - { - Q_ASSERT( artistPtr.isNull() ); - --m_queryCount; // This query is done. New query is infosystem query - getAlbumFromInfoystem( albumPtr->artist()->name(), albumPtr->name() ); - } - else if ( !artistPtr.isNull() ) - { - Q_ASSERT( albumPtr.isNull() ); - --m_queryCount; - getTopTen( artistPtr->name() ); - } - } - else - { - onTracksAdded( tracks ); - } - -} - - void DropJob::removeDuplicates() { @@ -803,41 +746,8 @@ DropJob::removeRemoteSources() } -void -DropJob::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) -{ - if ( requestData.caller == s_dropJobInfoId ) - { - const Tomahawk::InfoSystem::InfoStringHash info = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - - const QString artist = info["artist"]; - const QString album = info["album"]; - - qDebug() << "Got requestData response for artist" << artist << "and album:" << album << output; - - QList< query_ptr > results; - - int i = 0; - foreach ( const QVariant& title, output.toMap().value( "tracks" ).toList() ) - { - results << Query::get( artist, title.toString(), QString(), uuid() ); - - if ( ++i == 10 ) // Only getting top ten for now. Would make sense to make it configurable - break; - } - - if ( results.isEmpty() ) - { - const QString which = album.isEmpty() ? "artist" : "album"; - JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "No tracks found for given %1" ).arg( which ), 5 ) ); - } - onTracksAdded( results ); - } -} - - QList< query_ptr > -DropJob::getArtist( const QString &artist ) +DropJob::getArtist( const QString &artist, Tomahawk::ModelMode mode ) { artist_ptr artistPtr = Artist::get( artist ); if ( artistPtr->playlistInterface( Mixed )->tracks().isEmpty() ) @@ -845,13 +755,15 @@ DropJob::getArtist( const QString &artist ) m_artistsToKeep.insert( artistPtr ); connect( artistPtr.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), - SLOT( tracksFromDB( QList ) ) ); + SLOT( onTracksAdded( QList ) ) ); + + m_dropJob << new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album ); + JobStatusView::instance()->model()->addJob( m_dropJob.last() ); m_queryCount++; - return QList< query_ptr >(); } - else - return artistPtr->playlistInterface( Mixed )->tracks(); + + return artistPtr->playlistInterface( Mixed )->tracks(); } @@ -872,62 +784,21 @@ DropJob::getAlbum( const QString& artist, const QString& album ) // the artist_ptr which means we never get the signal delivered. so we hold on to the album pointer till we're done m_albumsToKeep.insert( albumPtr ); - m_dropJob = new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album ); connect( albumPtr.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), - SLOT( tracksFromDB( QList ) ) ); - JobStatusView::instance()->model()->addJob( m_dropJob ); + SLOT( onTracksAdded( QList ) ) ); + + m_dropJob << new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album ); + JobStatusView::instance()->model()->addJob( m_dropJob.last() ); m_queryCount++; - return QList< query_ptr >(); } - else - return albumPtr->playlistInterface( Mixed )->tracks(); + + return albumPtr->playlistInterface( Mixed )->tracks(); } -void -DropJob::getTopTen( const QString &artist ) +QList< query_ptr > +DropJob::getTopTen( const QString& artist ) { - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist; - - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = s_dropJobInfoId; - requestData.customData = QVariantMap(); - - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoArtistSongs; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - m_queryCount++; + return getArtist( artist, Tomahawk::InfoSystemMode ); } - - -void -DropJob::getAlbumFromInfoystem( const QString& artist, const QString& album ) -{ - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist; - artistInfo["album"] = album; - - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = s_dropJobInfoId; - requestData.customData = QVariantMap(); - - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - - requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - m_queryCount++; -} - diff --git a/src/libtomahawk/DropJob.h b/src/libtomahawk/DropJob.h index 8ae990352..272a6d338 100644 --- a/src/libtomahawk/DropJob.h +++ b/src/libtomahawk/DropJob.h @@ -22,9 +22,6 @@ #include "Query.h" -#include "infosystem/InfoSystem.h" -#include "utils/XspfLoader.h" - #include #include #include @@ -120,9 +117,7 @@ signals: private slots: void expandedUrls( QStringList ); void onTracksAdded( const QList& ); - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - void tracksFromDB( const QList< Tomahawk::query_ptr >& ); private: /// handle parsing mime data void handleAllUrls( const QString& urls ); @@ -133,11 +128,9 @@ private: QList< Tomahawk::query_ptr > tracksFromAlbumMetaData( const QMimeData* d ); QList< Tomahawk::query_ptr > tracksFromMixedData( const QMimeData* d ); - QList< Tomahawk::query_ptr > getArtist( const QString& artist ); + QList< Tomahawk::query_ptr > getArtist( const QString& artist, Tomahawk::ModelMode mode = Tomahawk::Mixed ); QList< Tomahawk::query_ptr > getAlbum( const QString& artist, const QString& album ); - - void getTopTen( const QString& artist ); - void getAlbumFromInfoystem( const QString& artist, const QString& album ); + QList< Tomahawk::query_ptr > getTopTen( const QString& artist ); void removeDuplicates(); void removeRemoteSources(); @@ -151,7 +144,7 @@ private: DropTypes m_dropTypes; DropAction m_dropAction; - Tomahawk::DropJobNotifier* m_dropJob; + QList m_dropJob; QList< Tomahawk::query_ptr > m_resultList; QSet< Tomahawk::album_ptr > m_albumsToKeep; From 3b0449866152f12da625cf15916ad06c167a2d21 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 16:32:29 +0200 Subject: [PATCH 139/433] * Make sure we always have a working uuid in Artist / Album. --- src/libtomahawk/Album.cpp | 18 +++++++++++++----- src/libtomahawk/Album.h | 1 + src/libtomahawk/Artist.cpp | 25 +++++++++++++++---------- src/libtomahawk/Artist.h | 1 + 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/libtomahawk/Album.cpp b/src/libtomahawk/Album.cpp index ca05f53d8..909f17fe2 100644 --- a/src/libtomahawk/Album.cpp +++ b/src/libtomahawk/Album.cpp @@ -115,14 +115,12 @@ Album::cover( const QSize& size, bool forceLoad ) const if ( !forceLoad ) return QPixmap(); - m_uuid = uuid(); - Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["artist"] = artist()->name(); trackInfo["album"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt; requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); requestData.customData = QVariantMap(); @@ -170,7 +168,7 @@ Album::cover( const QSize& size, bool forceLoad ) const void Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, const QVariant& output ) { - if ( requestData.caller != m_uuid || + if ( requestData.caller != infoid() || requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt ) { return; @@ -193,7 +191,7 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, void Album::infoSystemFinished( const QString& target ) { - if ( target != m_uuid ) + if ( target != infoid() ) return; disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), @@ -230,3 +228,13 @@ Album::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection ) { return playlistInterface( mode, collection )->tracks(); } + + +QString +Album::infoid() const +{ + if ( m_uuid.isEmpty() ) + m_uuid = uuid(); + + return m_uuid; +} \ No newline at end of file diff --git a/src/libtomahawk/Album.h b/src/libtomahawk/Album.h index eae36af96..89c6ad09f 100644 --- a/src/libtomahawk/Album.h +++ b/src/libtomahawk/Album.h @@ -77,6 +77,7 @@ private slots: private: Q_DISABLE_COPY( Album ) + QString infoid() const; unsigned int m_id; QString m_name; diff --git a/src/libtomahawk/Artist.cpp b/src/libtomahawk/Artist.cpp index c36e64ea2..1a85915ad 100644 --- a/src/libtomahawk/Artist.cpp +++ b/src/libtomahawk/Artist.cpp @@ -111,9 +111,6 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con if ( !collection.isNull() ) dbLoaded = false; - m_uuid = uuid(); - tDebug() << Q_FUNC_INFO << mode; - if ( ( mode == DatabaseMode || mode == Mixed ) && !dbLoaded ) { DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( collection, artist ); @@ -131,7 +128,7 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con artistInfo["artist"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); requestData.type = Tomahawk::InfoSystem::InfoArtistReleases; @@ -171,7 +168,7 @@ Artist::similarArtists() const artistInfo["artist"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.customData = QVariantMap(); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); @@ -259,7 +256,7 @@ Artist::onAlbumsFound( const QList< album_ptr >& albums, const QVariant& data ) void Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) { - if ( requestData.caller != m_uuid ) + if ( requestData.caller != infoid() ) return; QVariantMap returnedData = output.value< QVariantMap >(); @@ -274,7 +271,6 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari QList< album_ptr > albums; foreach ( const QString& albumName, albumNames ) { - tDebug() << Q_FUNC_INFO << albumName; Tomahawk::album_ptr album = Tomahawk::Album::get( m_ownRef.toStrongRef(), albumName, false ); m_officialAlbums << album; albums << album; @@ -328,7 +324,7 @@ Artist::infoSystemFinished( QString target ) { Q_UNUSED( target ); - if ( target != m_uuid ) + if ( target != infoid() ) return; if ( --m_infoJobs == 0 ) @@ -352,13 +348,12 @@ Artist::cover( const QSize& size, bool forceLoad ) const { if ( !forceLoad ) return QPixmap(); - m_uuid = uuid(); Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["artist"] = name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_uuid; + requestData.caller = infoid(); requestData.type = Tomahawk::InfoSystem::InfoArtistImages; requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); requestData.customData = QVariantMap(); @@ -428,3 +423,13 @@ Artist::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection ) { return playlistInterface( mode, collection )->tracks(); } + + +QString +Artist::infoid() const +{ + if ( m_uuid.isEmpty() ) + m_uuid = uuid(); + + return m_uuid; +} diff --git a/src/libtomahawk/Artist.h b/src/libtomahawk/Artist.h index cf267df1e..deeb2fb21 100644 --- a/src/libtomahawk/Artist.h +++ b/src/libtomahawk/Artist.h @@ -88,6 +88,7 @@ private slots: private: Artist(); + QString infoid() const; unsigned int m_id; QString m_name; From ab86a48ef745021471bd706c4f6b88f700c1c9ae Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 17:45:00 +0200 Subject: [PATCH 140/433] * Style fixes for WidgetDragFilter. --- src/libtomahawk/utils/WidgetDragFilter.cpp | 57 +++++++++++++--------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/libtomahawk/utils/WidgetDragFilter.cpp b/src/libtomahawk/utils/WidgetDragFilter.cpp index 46797ca46..3d427d097 100644 --- a/src/libtomahawk/utils/WidgetDragFilter.cpp +++ b/src/libtomahawk/utils/WidgetDragFilter.cpp @@ -38,34 +38,42 @@ WidgetDragFilter::WidgetDragFilter( QObject* parent ) bool WidgetDragFilter::eventFilter( QObject* obj, QEvent* event ) { - if( m_target.isNull() || m_target.data() != obj ) + if ( m_target.isNull() || m_target.data() != obj ) return false; - if( event->type() == QEvent::MouseButtonPress ) { + if ( event->type() == QEvent::MouseButtonPress ) + { QMouseEvent *mouseEvent = static_cast( event ); - if( !canDrag( obj, mouseEvent ) ) + if ( !canDrag( obj, mouseEvent ) ) return false; - if( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) ) + if ( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) ) return false; + m_dragPoint = mouseEvent->pos(); m_dragStarted = true; return false; - } else if( event->type() == QEvent::MouseMove ) { - if( !m_dragStarted ) + } + else if ( event->type() == QEvent::MouseMove ) + { + if ( !m_dragStarted ) return false; - QMouseEvent* e = static_cast(event); - if( !canDrag( obj, e ) ) { - m_dragStarted = false; + QMouseEvent* e = static_cast(event); + if ( !canDrag( obj, e ) ) + { + m_dragStarted = false; return false; } - if( e->buttons().testFlag( Qt::LeftButton ) ) { + + if ( e->buttons().testFlag( Qt::LeftButton ) ) + { m_target.data()->window()->move( m_target.data()->window()->pos() + ( e->pos() - m_dragPoint ) ); return true; } - } else if( event->type() == QEvent::MouseButtonRelease ) { - m_dragStarted = false; } + else if ( event->type() == QEvent::MouseButtonRelease ) + m_dragStarted = false; + return false; } @@ -76,38 +84,39 @@ WidgetDragFilter::eventFilter( QObject* obj, QEvent* event ) bool WidgetDragFilter::canDrag( QObject* obj, QMouseEvent* ev ) const { - if( !obj->isWidgetType() ) + if ( !obj->isWidgetType() ) return false; QWidget* w = static_cast< QWidget* >( obj ); - if( QWidget::mouseGrabber() ) + if ( QWidget::mouseGrabber() ) return false; - if( w->cursor().shape() != Qt::ArrowCursor ) + if ( w->cursor().shape() != Qt::ArrowCursor ) return false; // Now we check various things about the child position and mouse QPoint position( ev->pos() ); QWidget* child = w->childAt( position ); - if( child && child->cursor().shape() != Qt::ArrowCursor ) return false; + if ( child && child->cursor().shape() != Qt::ArrowCursor ) + return false; // Don't want to drag menubars when selecting an action - if( QMenuBar* menuBar = qobject_cast( w ) ) + if ( QMenuBar* menuBar = qobject_cast( w ) ) { // check if there is an active action - if( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) return false; + if ( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) + return false; // check if action at position exists and is enabled - if( QAction* action = menuBar->actionAt( position ) ) + if ( QAction* action = menuBar->actionAt( position ) ) { - if( action->isSeparator() ) return true; - if( action->isEnabled() ) return false; + if ( action->isSeparator() ) + return true; + if ( action->isEnabled() ) + return false; } - // return true in all other cases - return true; - } return true; From fac2e2fc5b688bb5f4d8b470da01166317a0960b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 17:45:40 +0200 Subject: [PATCH 141/433] * Make HeaderLabel an alternative drag-for-resize method. --- src/libtomahawk/widgets/HeaderLabel.cpp | 37 +++++++++++++++++++++++-- src/libtomahawk/widgets/HeaderLabel.h | 6 ++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/widgets/HeaderLabel.cpp b/src/libtomahawk/widgets/HeaderLabel.cpp index cfd3542a9..edec62258 100644 --- a/src/libtomahawk/widgets/HeaderLabel.cpp +++ b/src/libtomahawk/widgets/HeaderLabel.cpp @@ -20,17 +20,20 @@ #include #include +#include #include "utils/Logger.h" #include "utils/StyleHelper.h" #include "utils/TomahawkUtilsGui.h" - static const int s_defaultFontSize = 12; + HeaderLabel::HeaderLabel( QWidget* parent ) : QLabel( parent ) , m_parent( parent ) + , m_pressed( false ) + , m_moved( false ) { QFont f( font() ); f.setBold( true ); @@ -38,6 +41,7 @@ HeaderLabel::HeaderLabel( QWidget* parent ) setFont( f ); setFixedHeight( TomahawkUtils::headerHeight() ); + setMouseTracking( true ); } @@ -52,6 +56,7 @@ HeaderLabel::sizeHint() const return QLabel::sizeHint(); } + int HeaderLabel::defaultFontSize() { @@ -63,7 +68,14 @@ void HeaderLabel::mousePressEvent( QMouseEvent* event ) { QFrame::mousePressEvent( event ); - m_time.start(); + + if ( !m_moved ) + { + m_time.start(); + + m_pressed = true; + m_dragPoint = event->pos(); + } } @@ -71,8 +83,27 @@ void HeaderLabel::mouseReleaseEvent( QMouseEvent* event ) { QFrame::mouseReleaseEvent( event ); - if ( m_time.elapsed() < qApp->doubleClickInterval() ) + + if ( !m_moved && m_time.elapsed() < qApp->doubleClickInterval() ) emit clicked(); + + m_pressed = false; + m_moved = false; +} + + +void +HeaderLabel::mouseMoveEvent( QMouseEvent* event ) +{ + if ( m_pressed ) + { + QPoint delta = m_dragPoint - event->pos(); + if ( abs( delta.y() ) > 3 ) + { + m_moved = true; + emit resized( delta ); + } + } } diff --git a/src/libtomahawk/widgets/HeaderLabel.h b/src/libtomahawk/widgets/HeaderLabel.h index 4d015d5c9..88f244c7e 100644 --- a/src/libtomahawk/widgets/HeaderLabel.h +++ b/src/libtomahawk/widgets/HeaderLabel.h @@ -43,6 +43,7 @@ public: signals: void clicked(); + void resized( const QPoint& delta ); protected: // void changeEvent( QEvent* e ); @@ -50,10 +51,15 @@ protected: void mousePressEvent( QMouseEvent* event ); void mouseReleaseEvent( QMouseEvent* event ); + void mouseMoveEvent( QMouseEvent* event ); private: QWidget* m_parent; QTime m_time; + + QPoint m_dragPoint; + bool m_pressed; + bool m_moved; }; #endif // HEADERLABEL_H From 84c40dc590fbc9b6fb41a00d9f7eaa146b02134e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 17:46:11 +0200 Subject: [PATCH 142/433] * Support manual resizing in AnimatedSplitter. --- src/libtomahawk/widgets/AnimatedSplitter.cpp | 80 ++++++++++++++------ src/libtomahawk/widgets/AnimatedSplitter.h | 9 ++- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/libtomahawk/widgets/AnimatedSplitter.cpp b/src/libtomahawk/widgets/AnimatedSplitter.cpp index 93a941c83..26a483266 100644 --- a/src/libtomahawk/widgets/AnimatedSplitter.cpp +++ b/src/libtomahawk/widgets/AnimatedSplitter.cpp @@ -63,6 +63,7 @@ AnimatedSplitter::addWidget( AnimatedWidget* widget ) connect( widget, SIGNAL( hideWidget() ), SLOT( onHideRequest() ) ); connect( widget, SIGNAL( sizeHintChanged( QSize ) ), SLOT( onShowRequest() ) ); connect( widget, SIGNAL( sizeChanged( QSize ) ), SLOT( onSizeChanged( QSize ) ) ); + connect( widget, SIGNAL( resizeBy( QPoint ) ), SLOT( onResizeRequest( QPoint ) ) ); connect( this, SIGNAL( shown( QWidget*, bool ) ), widget, SLOT( onShown( QWidget*, bool ) ) ); connect( this, SIGNAL( hidden( QWidget*, bool ) ), widget, SLOT( onHidden( QWidget*, bool ) ) ); @@ -70,32 +71,9 @@ AnimatedSplitter::addWidget( AnimatedWidget* widget ) void -AnimatedSplitter::onShowRequest() +AnimatedSplitter::changeSize( QWidget* child, const QSize& size ) { - AnimatedWidget* w = (AnimatedWidget*)(sender()); - if ( indexOf( w ) > 0 ) - show( indexOf( w ) ); - else - qDebug() << "Could not find widget:" << sender(); -} - - -void -AnimatedSplitter::onHideRequest() -{ - AnimatedWidget* w = (AnimatedWidget*)(sender()); - if ( indexOf( w ) > 0 ) - hide( indexOf( w ) ); - else - qDebug() << "Could not find widget:" << sender(); -} - - -void -AnimatedSplitter::onSizeChanged( const QSize& size ) -{ - AnimatedWidget* w = (AnimatedWidget*)(sender()); - int wi = indexOf( w ); + int wi = indexOf( child ); QList< int > sizes; for ( int i = 0; i < count(); i ++ ) @@ -127,6 +105,58 @@ AnimatedSplitter::onSizeChanged( const QSize& size ) } +void +AnimatedSplitter::onResizeRequest( const QPoint& delta ) +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + { + int newheight = w->height() + delta.y(); + if ( newheight <= w->hiddenSize().height() ) + { + w->hide(); + } + else + changeSize( w, QSize( w->width(), newheight ) ); + } + else + Q_ASSERT( false ); +} + + +void +AnimatedSplitter::onShowRequest() +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + show( indexOf( w ) ); + else + Q_ASSERT( false ); +} + + +void +AnimatedSplitter::onHideRequest() +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + hide( indexOf( w ) ); + else + Q_ASSERT( false ); +} + + +void +AnimatedSplitter::onSizeChanged( const QSize& size ) +{ + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + changeSize( w, size ); + else + Q_ASSERT( false ); +} + + void AnimatedSplitter::setGreedyWidget( int index ) { diff --git a/src/libtomahawk/widgets/AnimatedSplitter.h b/src/libtomahawk/widgets/AnimatedSplitter.h index 4e47d77b9..a8ef35325 100644 --- a/src/libtomahawk/widgets/AnimatedSplitter.h +++ b/src/libtomahawk/widgets/AnimatedSplitter.h @@ -49,11 +49,14 @@ protected: virtual QSplitterHandle* createHandle(); private slots: + void changeSize( QWidget* child, const QSize& size ); + void onShowRequest(); void onHideRequest(); void onSizeChanged( const QSize& size ); - + void onResizeRequest( const QPoint& delta ); + private: int m_greedyIndex; }; @@ -95,10 +98,14 @@ public slots: virtual void onShown( QWidget*, bool animated ); virtual void onHidden( QWidget*, bool animated ); + virtual void hide() { emit hideWidget(); } + virtual void show() { emit showWidget(); } + signals: void showWidget(); void hideWidget(); + void resizeBy( const QPoint& delta ); void sizeChanged( const QSize& size ); void sizeHintChanged( const QSize& size ); void hiddenSizeChanged(); From 22d65b7364c626a1e005cc7e152e1f3f63019d8e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 17:46:30 +0200 Subject: [PATCH 143/433] * Make QueueView's header draggable for resizing. --- src/libtomahawk/playlist/QueueView.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 0c4985bdc..9062f081e 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -50,6 +50,7 @@ QueueView::QueueView( AnimatedSplitter* parent ) connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); ui->toggleButton->installEventFilter( this ); + ui->toggleButton->setCursor( Qt::PointingHandCursor ); } @@ -116,8 +117,11 @@ QueueView::hide() { disconnect( ui->toggleButton, SIGNAL( clicked() ), this, SLOT( hide() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); + disconnect( ui->toggleButton, SIGNAL( resized( QPoint ) ), this, SIGNAL( resizeBy( QPoint ) ) ); + ui->toggleButton->setText( tr( "Show Queue" ) ); - emit hideWidget(); + + AnimatedWidget::hide(); } @@ -126,8 +130,10 @@ QueueView::show() { disconnect( ui->toggleButton, SIGNAL( clicked() ), this, SLOT( show() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( hide() ) ); + connect( ui->toggleButton, SIGNAL( resized( QPoint ) ), SIGNAL( resizeBy( QPoint ) ) ); + ui->toggleButton->setText( tr( "Hide Queue" ) ); - emit showWidget(); + AnimatedWidget::show(); } From e06f58eb29a3f648909062e1bf19004fda905456 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 19:00:29 +0200 Subject: [PATCH 144/433] * Properly init StopAfterPlayback action. --- src/TomahawkTrayIcon.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/TomahawkTrayIcon.cpp b/src/TomahawkTrayIcon.cpp index 6c4b40efe..6c75a8552 100644 --- a/src/TomahawkTrayIcon.cpp +++ b/src/TomahawkTrayIcon.cpp @@ -92,6 +92,7 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) connect( &m_animationTimer, SIGNAL( timeout() ), SLOT( onAnimationTimer() ) ); connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), SLOT( onActivated( QSystemTrayIcon::ActivationReason ) ) ); + onStop(); show(); } @@ -241,6 +242,7 @@ void TomahawkTrayIcon::onPlay() { m_stopContinueAfterTrackAction->setEnabled( true ); + onResume(); onStopContinueAfterTrackChanged(); } @@ -250,6 +252,7 @@ void TomahawkTrayIcon::onStop() { m_stopContinueAfterTrackAction->setEnabled( false ); + onPause(); } @@ -264,12 +267,12 @@ TomahawkTrayIcon::onResume() void TomahawkTrayIcon::onStopContinueAfterTrackChanged() { + m_stopContinueAfterTrackAction->setText( tr( "&Stop Playback after current Track" ) ); + if ( !AudioEngine::instance()->currentTrack().isNull() ) { if ( AudioEngine::instance()->currentTrack()->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) m_stopContinueAfterTrackAction->setText( tr( "&Continue Playback after current Track" ) ); - else - m_stopContinueAfterTrackAction->setText( tr( "&Stop Playback after current Track" ) ); } } From 7cf307080b9eb75b0056580e266d8ee57c7ca63e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 19:00:53 +0200 Subject: [PATCH 145/433] * Split audioStopped / audioPaused into separate slots. --- src/TomahawkWindow.cpp | 24 ++++++++++++++++-------- src/TomahawkWindow.h | 1 + 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index a2856014c..3f30045c6 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -120,6 +120,8 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) // set initial state onAccountDisconnected(); + audioStopped(); + vm->setQueue( m_queueView ); vm->showWelcomePage(); } @@ -335,7 +337,7 @@ TomahawkWindow::setupSignals() connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) ); connect( AudioEngine::instance(), SIGNAL( resumed()), SLOT( audioStarted() ) ); - connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioStopped() ) ); + connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) ); //

    @@ -778,21 +780,27 @@ void TomahawkWindow::audioStarted() { m_audioRetryCounter = 0; + ui->actionPlay->setText( tr( "Pause" ) ); + ActionCollection::instance()->getAction( "stop" )->setEnabled( true ); +} + + +void +TomahawkWindow::audioPaused() +{ + ui->actionPlay->setText( tr( "Play" ) ); } void TomahawkWindow::audioStopped() { - ui->actionPlay->setText( tr( "Play" ) ); + audioPaused(); + ActionCollection::instance()->getAction( "stop" )->setEnabled( false ); - tDebug() << Q_FUNC_INFO << AudioEngine::instance()->isStopped(); - if ( AudioEngine::instance()->isStopped() ) - { - m_currentTrack = result_ptr(); - setWindowTitle( m_windowTitle ); - } + m_currentTrack = result_ptr(); + setWindowTitle( m_windowTitle ); } diff --git a/src/TomahawkWindow.h b/src/TomahawkWindow.h index a0bde3cda..f84965e20 100644 --- a/src/TomahawkWindow.h +++ b/src/TomahawkWindow.h @@ -110,6 +110,7 @@ private slots: void onPlaybackLoading( const Tomahawk::result_ptr& result ); void audioStarted(); + void audioPaused(); void audioStopped(); void showAboutTomahawk(); From 1528095de2a445071db7386e9fd96c784f4b2dba Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 19:38:40 +0200 Subject: [PATCH 146/433] * No need to call loadSocialActions manually. --- src/libtomahawk/ContextMenu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/ContextMenu.cpp b/src/libtomahawk/ContextMenu.cpp index 60eecc663..1b562b093 100644 --- a/src/libtomahawk/ContextMenu.cpp +++ b/src/libtomahawk/ContextMenu.cpp @@ -98,7 +98,6 @@ ContextMenu::setQueries( const QList& queries ) m_sigmap->setMapping( m_loveAction, ActionLove ); connect( queries.first().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) ); - m_queries.first()->loadSocialActions(); onSocialActionsLoaded(); } From 96132ef9c675f5a8edb6c46bc6d4f9a60e055407 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 28 May 2012 19:38:57 +0200 Subject: [PATCH 147/433] * Added love track action to the tray menu. --- src/TomahawkTrayIcon.cpp | 77 ++++++++++++++++++++++++++++++---------- src/TomahawkTrayIcon.h | 4 +++ 2 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/TomahawkTrayIcon.cpp b/src/TomahawkTrayIcon.cpp index 6c75a8552..edcf2483c 100644 --- a/src/TomahawkTrayIcon.cpp +++ b/src/TomahawkTrayIcon.cpp @@ -40,6 +40,7 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) , m_currentAnimationFrame( 0 ) , m_showWindowAction( 0 ) , m_stopContinueAfterTrackAction( 0 ) + , m_loveTrackAction( 0 ) { #ifdef Q_WS_MAC QIcon icon( RESPATH "icons/tomahawk-icon-128x128-grayscale.png" ); @@ -54,12 +55,14 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu = new QMenu(); setContextMenu( m_contextMenu ); + m_loveTrackAction = new QAction( this ); m_stopContinueAfterTrackAction = new QAction( this ); - onStopContinueAfterTrackChanged(); ActionCollection *ac = ActionCollection::instance(); m_contextMenu->addAction( ac->getAction( "playPause" ) ); m_contextMenu->addAction( ac->getAction( "stop" ) ); + m_contextMenu->addSeparator(); + m_contextMenu->addAction( m_loveTrackAction ); m_contextMenu->addAction( m_stopContinueAfterTrackAction ); m_contextMenu->addSeparator(); m_contextMenu->addAction( ac->getAction( "previousTrack" ) ); @@ -67,8 +70,6 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu->addSeparator(); m_contextMenu->addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) ); - connect( m_stopContinueAfterTrackAction, SIGNAL( triggered() ), SLOT( stopContinueAfterTrackActionTriggered() ) ); - #ifdef Q_WS_MAC // On mac you can close the windows while leaving the app open. We then need a way to show the main window again m_contextMenu->addSeparator(); @@ -82,6 +83,9 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) m_contextMenu->addSeparator(); m_contextMenu->addAction( ac->getAction( "quit" ) ); + connect( m_loveTrackAction, SIGNAL( triggered() ), SLOT( loveTrackTriggered() ) ); + connect( m_stopContinueAfterTrackAction, SIGNAL( triggered() ), SLOT( stopContinueAfterTrackActionTriggered() ) ); + connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( setResult( Tomahawk::result_ptr ) ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlay() ) ); connect( AudioEngine::instance(), SIGNAL( resumed() ), SLOT( onResume() ) ); @@ -152,8 +156,29 @@ TomahawkTrayIcon::menuAboutToShow() void TomahawkTrayIcon::setResult( const Tomahawk::result_ptr& result ) { + if ( m_currentTrack ) + { + disconnect( m_currentTrack->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( onSocialActionsLoaded() ) ); + } + m_currentTrack = result; refreshToolTip(); + + if ( result ) + connect( result->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ), Qt::UniqueConnection ); + + onSocialActionsLoaded(); + onStopContinueAfterTrackChanged(); +} + + +void +TomahawkTrayIcon::onStopContinueAfterTrackChanged() +{ + if ( m_currentTrack && m_currentTrack->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) + m_stopContinueAfterTrackAction->setText( tr( "&Continue Playback after current Track" ) ); + else + m_stopContinueAfterTrackAction->setText( tr( "&Stop Playback after current Track" ) ); } @@ -241,18 +266,20 @@ TomahawkTrayIcon::onPause() void TomahawkTrayIcon::onPlay() { + m_loveTrackAction->setEnabled( true ); m_stopContinueAfterTrackAction->setEnabled( true ); onResume(); - onStopContinueAfterTrackChanged(); } void TomahawkTrayIcon::onStop() { + m_loveTrackAction->setEnabled( false ); m_stopContinueAfterTrackAction->setEnabled( false ); + setResult( Tomahawk::result_ptr() ); onPause(); } @@ -265,26 +292,41 @@ TomahawkTrayIcon::onResume() void -TomahawkTrayIcon::onStopContinueAfterTrackChanged() +TomahawkTrayIcon::loveTrackTriggered() { - m_stopContinueAfterTrackAction->setText( tr( "&Stop Playback after current Track" ) ); + if ( !m_currentTrack ) + return; - if ( !AudioEngine::instance()->currentTrack().isNull() ) - { - if ( AudioEngine::instance()->currentTrack()->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) - m_stopContinueAfterTrackAction->setText( tr( "&Continue Playback after current Track" ) ); - } + m_currentTrack->toQuery()->setLoved( !m_currentTrack->toQuery()->loved() ); } -void TomahawkTrayIcon::stopContinueAfterTrackActionTriggered() +void +TomahawkTrayIcon::stopContinueAfterTrackActionTriggered() { - if ( !AudioEngine::instance()->currentTrack().isNull() ) + if ( !m_currentTrack ) + return; + + if ( !m_currentTrack->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) + AudioEngine::instance()->setStopAfterTrack( m_currentTrack->toQuery() ); + else + AudioEngine::instance()->setStopAfterTrack( Tomahawk::query_ptr() ); +} + + +void +TomahawkTrayIcon::onSocialActionsLoaded() +{ + m_loveTrackAction->setText( tr( "&Love" ) ); + m_loveTrackAction->setIcon( QIcon( RESPATH "images/loved.png" ) ); + + if ( !m_currentTrack ) + return; + + if ( m_currentTrack->toQuery()->loved() ) { - if ( !AudioEngine::instance()->currentTrack()->toQuery()->equals( AudioEngine::instance()->stopAfterTrack() ) ) - AudioEngine::instance()->setStopAfterTrack( AudioEngine::instance()->currentTrack()->toQuery() ); - else - AudioEngine::instance()->setStopAfterTrack( Tomahawk::query_ptr() ); + m_loveTrackAction->setText( tr( "Un-&Love" ) ); + m_loveTrackAction->setIcon( QIcon( RESPATH "images/not-loved.png" ) ); } } @@ -310,4 +352,3 @@ TomahawkTrayIcon::event( QEvent* e ) return QSystemTrayIcon::event( e ); } - diff --git a/src/TomahawkTrayIcon.h b/src/TomahawkTrayIcon.h index d1c73f41c..31984492b 100644 --- a/src/TomahawkTrayIcon.h +++ b/src/TomahawkTrayIcon.h @@ -49,10 +49,13 @@ private slots: void onStop(); void onResume(); + void onSocialActionsLoaded(); void onStopContinueAfterTrackChanged(); void stopContinueAfterTrackActionTriggered(); + void loveTrackTriggered(); void menuAboutToShow(); + private: void refreshToolTip(); ~TomahawkTrayIcon(); @@ -67,6 +70,7 @@ private: QAction* m_showWindowAction; QAction* m_stopContinueAfterTrackAction; + QAction* m_loveTrackAction; }; #endif // TOMAHAWK_TRAYICON_H From 4113389cb565a67073e519eb7456ce15a47e6256 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Mon, 28 May 2012 22:16:57 +0000 Subject: [PATCH 148/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 244 ++++++++++++++++++++++------------------- lang/tomahawk_bg.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_ca.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_de.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_en.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_es.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_fr.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_ja.ts | 225 ++++++++++++++++++++----------------- lang/tomahawk_pl.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_pt_BR.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_ru.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_sv.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_tr.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_zh_CN.ts | 222 ++++++++++++++++++++----------------- lang/tomahawk_zh_TW.ts | 222 ++++++++++++++++++++----------------- 15 files changed, 1843 insertions(+), 1512 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 489ef9ad2..3ca6093af 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -22,17 +22,17 @@ Online - على الهواء + متصل Connecting... - يجرى الاتصال... + جاري الاتصال... Offline - خارج الهواء + غير متصل @@ -56,12 +56,12 @@ connect and stream from you? &Listen Along - &تابع الاستماع + &استمع مع Stop &Listening Along - توقيف &متابعة الإستماع + توقيف &الاستماع مع @@ -332,7 +332,7 @@ connect and stream from you? Clear - حذف + مسح @@ -361,7 +361,7 @@ connect and stream from you? InfoBar - InfoBar + شريط المعلومات @@ -400,7 +400,7 @@ connect and stream from you? Abort - اجهاض + الغاء @@ -410,13 +410,13 @@ connect and stream from you? Uploaded %L1 of %L2 KB. - تحميل %L1 من أصل %L2 كب. + تحميل %L1 من أصل %L2 كيلو بايت. Close - غلق + اغلاق @@ -473,14 +473,6 @@ connect and stream from you? نسخ إلى الحافظة - - DropJob - - - No tracks found for given %1 - لم يتم إيجاد أي أغاني ل%1 - - GlobalSearchWidget @@ -801,7 +793,7 @@ connect and stream from you? Create Automatic Playlist - إنشاء قائمة أغاني جديدة أوتوماتيكيا + إنشاء قائمة أغاني جديدة أوتوماتيكية @@ -973,12 +965,12 @@ connect and stream from you? - + Show Queue أظهر قائمة الانتظار - + Hide Queue إخفي قائمة الانتظار @@ -1299,38 +1291,38 @@ connect and stream from you? &تصدير قائمة الأغاني - + playlist قائمة الأغاني - + automatic playlist قائمة أغاني أوتوماتيكية - + station إذاعة - + Delete %1? playlist/station/... أحذف %1؟ - + Would you like to delete the %1 <b>"%2"</b>? هل ترغب في حذف %1 <b> "%2" </b>؟ - + Save XSPF حفظ XSPF - + Playlists (*.xspf) قوائم أغاني (*.xspf) @@ -1610,32 +1602,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account أضف حساب - + Remove Account حذف الحساب - + %1 downloads تحميل %1 - + Online على الهواء - + Connecting... يجرى الاتصال... - + Offline خارج الهواء @@ -1966,29 +1958,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue أضف إلى &قائمة الانتظار - + &Love &أحب - + &Copy Track Link &إنسخ رابط الأغنية - + Un-&Love لا &أحب - + &Delete Items &أحذف البنود @@ -2003,22 +1995,22 @@ You may wish to try re-authenticating. &أوقف الاستماع بعد هذه الأغنية - + &Show Track Page &أظهر صفحة الأغاني - + &Delete Item &أحذف البند - + &Show Album Page &أظهر صفحة الألبومات - + &Show Artist Page &أظهر صفحة الفنان @@ -2059,12 +2051,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + قائمة الأغاني + + + + artist + فنان + + + + track + اغنية + + + + album + البوم + + + Fetching %1 from database جلب %1 من قاعدة البيانات - + Parsing %1 %2 تحليل %1 %2 @@ -2806,38 +2818,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &أوقف الاستماع بعد الأغنية الحالية - - + + Hide Tomahawk Window إخفي نافذة توماهوك - + Show Tomahawk Window أظهر نافذة توماهوك - + Currently not playing. لا يتم الاستماع حاليا. - + Play إستمع - + Pause تعليق - + + &Love + &أحب + + + + Un-&Love + لا &أحب + + + &Continue Playback after current Track &أكمل الاستماع بعد الأغنية الحالية @@ -2981,7 +3003,7 @@ enter the displayed PIN number here: - + Play إستمع @@ -3001,167 +3023,167 @@ enter the displayed PIN number here: التالي - + Back إلى الوراء - + Go back one page العودة صفحة واحدة إلى الوراء - + Forward تقدم - + Go forward one page تقدم صفحة واحدة - + Global Search... بحث شامل... - - + + Check For Updates... التحقق من التحديثات... - - - + + + Connect To Peer ربط بالند - + Enter peer address: أدخل عنوان الند: - + Enter peer port: أدخل بوابة الند: - + Enter peer key: أدخل مفتاح الند: - + XSPF Error خطأ XSPF - + This is not a valid XSPF playlist. قائمة الأغاني XSPF هذه ليست صالحة. - + Failed to save tracks فشل في حفظ الأغاني - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. - + Create New Station إنشاء قائمة أغاني جديدة - + Name: الاسم: - + New Station إذاعة جديدة - + New Playlist قائمة أغاني جديدة - + Pause تعليق - + Go &offline إذهب &خارج الهواء - + Go &online إذهب &على الهواء - + Authentication Error خطأ في المصادقة - + Error connecting to SIP: Authentication failed! خطأ في الاتصال بسيب (SIP): فشلت المصادقة! - + %1 by %2 track, artist name %1 من قبل %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ - + Thanks to: شكر لكل من: - + About Tomahawk عن توماهوك @@ -3773,107 +3795,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction تفاعل المستخدم - + Host is unknown المضيف مجهول - + Item not found البند غير موجودة - + Authorization Error خطا في الترخيص - + Remote Stream Error خطأ في التحميل (المجرى) البعيد - + Remote Connection failed فشل في الاتصال البعيد - + Internal Server Error خطأ داخلي في الخادم - + System shutdown إغلاق النظام - + Conflict تضارب - + Unknown مجهول - + No Compression Support لا دعم للضغط - + No Encryption Support لا دعم للتشفير - + No Authorization Support لا دعم للترخيص - + No Supported Feature لا ميزة معتمدة - + Add Friend أضف صديق - + Enter Xmpp ID: أدخل تعريف أكسمبب (XMPP ID): - + Add Friend... أضف صديق... - + XML Console... وحدة التحكم XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! أنا أسف... أنا مجرد وجود ألي مستخدم من قبل توماهوك (http://gettomahawk.com). في حال الحصول على هذه الرسالة، فإن الشخص اللذي تحاول الوصول إليه خارج الخدمة، فنرجو المحاولة لاحقاً! - + Authorize User أعطي الإذن للمستخدم - + Do you want to grant <b>%1</b> access to your Collection? هل تريد أن تسمح ل <b>%1</b> بالوصول إلى مجموعتك ؟ diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index ade16ac2f..4bf0686fb 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -476,14 +476,6 @@ Tomahaw създаде доклад относно това и изпращай Копирай в буферът - - DropJob - - - No tracks found for given %1 - Няма открити изпълнения на %1 - - GlobalSearchWidget @@ -974,12 +966,12 @@ Tomahaw създаде доклад относно това и изпращай - + Show Queue Покажи опашката - + Hide Queue Скрий опашката @@ -1301,38 +1293,38 @@ Tomahaw създаде доклад относно това и изпращай &Изнеси списък - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -1614,32 +1606,32 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountDelegate - + Add Account Добави регистрация - + Remove Account Премахни регистрация - + %1 downloads %1 сваляния - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -1975,29 +1967,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Добави към &опашката - + &Love &Харесай - + &Copy Track Link &Копирай адресът на изпълнението - + Un-&Love Не-&харесай - + &Delete Items &Изтрий позициите @@ -2012,22 +2004,22 @@ You may wish to try re-authenticating. &Спри след тази песен - + &Show Track Page &Покажи страницата на песента - + &Delete Item &Изтрий позицията - + &Show Album Page &Покажи страницата на албума - + &Show Artist Page &Покажи страницата на артистът @@ -2068,12 +2060,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Извличане на %1 от БД - + Parsing %1 %2 Обединяване на %1 %2 @@ -2814,38 +2826,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &Спри възпроизвеждането след текущата песен - - + + Hide Tomahawk Window Скрий главният прозорец - + Show Tomahawk Window Покажи главният прозорец - + Currently not playing. В момента не се изпълнява нищо - + Play Изпълни - + Pause Пауза - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Продължи възпроизвеждането след текущата песен @@ -2989,7 +3011,7 @@ enter the displayed PIN number here: - + Play Изпълни @@ -3009,170 +3031,170 @@ enter the displayed PIN number here: Следваща - + Back - + Go back one page Една страница назад - + Forward Напред - + Go forward one page Една страница напред - + Global Search... Глобално търсене... - - + + Check For Updates... Провери за обновления... - - - + + + Connect To Peer Свържи се с друг потребител - + Enter peer address: Въведи адресът на отдалеченият потребител: - + Enter peer port: Въведи порт: - + Enter peer key: Въведи ключът за удостоверяване: - + XSPF Error XSPF Грешка - + This is not a valid XSPF playlist. Това не е валиден XSPF списък - + Failed to save tracks Не мога да запазя списъкът с песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Някои от песните в този списък нямат артист и заглавие. Те ще бъдат игнорирани. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраната песен - тя ще бъде прескочена. Моля, увери се, че са инсталирани подходящ Phonon и приставки. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Съжалявам. Има проблем с достъпа до твоето аудио устройство или избраната песен. Тя ще бъде пропусната. - + Create New Station Създай нова станция - + Name: Име: - + New Station Нова станция - + New Playlist Нов списък - + Pause Пауза - + Go &offline Излез &извън линия - + Go &online Свържи &се - + Authentication Error Грешка при удостоверяване - + Error connecting to SIP: Authentication failed! Грешка при свързване: Неуспешно удостоверяване! - + %1 by %2 track, artist name %1 от %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Всички права - запазени. 2010 - 2012 - + Thanks to: Благодарности на: - + About Tomahawk Относно Tomahawk @@ -3782,107 +3804,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Действие от потребителя - + Host is unknown Непознат адрес - + Item not found Обектът не е открит - + Authorization Error Грешка при даване на достъп - + Remote Stream Error Грешка в стриймът от отдалечената машина - + Remote Connection failed Отдалечената връзка е неуспешна - + Internal Server Error Вътрешна грешка на сървъра - + System shutdown Изключване на системата - + Conflict Конфликт - + Unknown Неизвестно - + No Compression Support Няма поддръжка на компресия - + No Encryption Support Няма поддръжка на криптиране - + No Authorization Support Няма поддръжка на удостоверяване - + No Supported Feature Неподдържана функция - + Add Friend Добави приятел - + Enter Xmpp ID: Въведи Xmpp ID: - + Add Friend... Добави приятел... - + XML Console... XML Конзола... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Извинявай.. Аз съм режимът за автоматични отговори изпълзван от Tomahawk. ( http://gettomahawk.com ) Щом получаваш това съобщение, този с който се опитваш да се свържеш вероятно не е на линия. Моля, опитай отново по-късно. - + Authorize User Оправомощяване на потребител - + Do you want to grant <b>%1</b> access to your Collection? Искате ли да позволите на <b>%1</b> достъп до вашата колекция? diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index cb29b0708..4141f67e4 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -472,14 +472,6 @@ connect and stream from you? Copia al Porta-retalls - - DropJob - - - No tracks found for given %1 - No s'han trobat cançons per %1 - - GlobalSearchWidget @@ -971,12 +963,12 @@ connect and stream from you? - + Show Queue Mostra la Cua - + Hide Queue Amaga la Cua @@ -1297,38 +1289,38 @@ connect and stream from you? E&xporta la Llista de Reproducció - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -1609,32 +1601,32 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountDelegate - + Add Account Afegeix un compte - + Remove Account Esborra el compte - + %1 downloads %1 descàrregues - + Online En Línia - + Connecting... Connectant-se... - + Offline Fora de Línia @@ -1965,29 +1957,29 @@ Torneu a autenticar-vos. - - + + Add to &Queue &Afegeix a la Cua - + &Love &M'encanta - + &Copy Track Link &Copia l'Enllaç de la Cançó - + Un-&Love &Treu de les preferides - + &Delete Items &Elimina els Ítems @@ -2002,22 +1994,22 @@ Torneu a autenticar-vos. &Atura la Reproducció després d'aquesta Cançó - + &Show Track Page - + &Delete Item &Elimina l'Ítem - + &Show Album Page - + &Show Artist Page @@ -2058,12 +2050,32 @@ Torneu a autenticar-vos. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Cercant %1 a la base de dades - + Parsing %1 %2 Analitzant %1 %2 @@ -2805,38 +2817,48 @@ introduïu el PIN aquí: TomahawkTrayIcon - + &Stop Playback after current Track &Atura la Reproducció després d'aquesta Cançó - - + + Hide Tomahawk Window Amaga la finestra de Tomahawk - + Show Tomahawk Window Mostra la finestra de Tomahawk - + Currently not playing. No s'està reproduint res. - + Play Reprodueix - + Pause Pausa - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Continua la reproducció després d'aquesta Cançó @@ -2980,7 +3002,7 @@ introduïu el PIN aquí: - + Play Reprodueix @@ -3000,167 +3022,167 @@ introduïu el PIN aquí: Següent - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Cerca Global... - - + + Check For Updates... Comprova les actualitzacions... - - - + + + Connect To Peer Connexió Remota - + Enter peer address: Introduïu l'adreça remota: - + Enter peer port: Introduïu el port remot: - + Enter peer key: Introduïu la clau remota: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. No és una llista XSPF vàlida. - + Failed to save tracks Error en desar les cançons - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunes cançons de la llista no contenen ni artista ni titol i s'han ignorat. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Hi ha un problema per accedir al dispositiu de so o a la cançó. La cançó actual s'ha saltat. Assegureu-vos que teniu un back.end de Phonon adequant i els plugins necessaris instal·lats. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Hi ha un problema per accedir al dispositiu de so o a la cançó, la cançó actual s'ha saltat. - + Create New Station Crea una Nova Emissora - + Name: Nom: - + New Station Nova Emissora - + New Playlist Nova llista de reproducció - + Pause Pausa - + Go &offline &Desconnecta't - + Go &online &Connecta't - + Authentication Error Error d'autentificació - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Quant a Tomahawk @@ -3770,107 +3792,107 @@ Lletres de la cancó "%1" de %2: XmppSipPlugin - + User Interaction Interacció d'usuari - + Host is unknown El nom de l'ordinador és desconegut - + Item not found No s'ha trobat l'element - + Authorization Error Error d'autorització - + Remote Stream Error Error de flux remot - + Remote Connection failed Ha fallat la connexió remota - + Internal Server Error Error del servidor intern - + System shutdown Sistema apagat - + Conflict Conflicte - + Unknown Desconegut - + No Compression Support Compressió no suportada - + No Encryption Support Encriptació no suportada - + No Authorization Support Autorització no suportada - + No Supported Feature Característica no suportada - + Add Friend Afegeix un Amic - + Enter Xmpp ID: Introduiu la ID XMPP: - + Add Friend... Afegeix un Amic... - + XML Console... Consola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Sóc una presència automàtica emprada pel Reproductor Tomahawk. (http://gettomahawk.com. Si rebeu aquest missatge, la persona amb qui intenteu contactar probablement no està en línia, intenteu-ho més tard! - + Authorize User Autorització d'Usuari - + Do you want to grant <b>%1</b> access to your Collection? Voleu permetre que <b>%1</b> accedeixi a la vostra Col·lecció? diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index e3d37a125..c4bd03f3e 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -472,14 +472,6 @@ connect and stream from you? In die Zwischenablage kopieren - - DropJob - - - No tracks found for given %1 - Keine Stücke gefunden für %1 - - GlobalSearchWidget @@ -971,12 +963,12 @@ connect and stream from you? - + Show Queue Warteschlange einblenden - + Hide Queue Warteschlange ausblenden @@ -1297,38 +1289,38 @@ connect and stream from you? Playliste &exportieren - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -1606,32 +1598,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Konto hinzufügen - + Remove Account Konto entfernen - + %1 downloads %1 Downloads - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -1960,29 +1952,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue In &Warteschlange einreihen - + &Love &Lieblingslied - + &Copy Track Link &Kopiere Link zu diesem Stück - + Un-&Love Kein &Lieblingslied - + &Delete Items Elemente &entfernen @@ -1997,22 +1989,22 @@ You may wish to try re-authenticating. Wiedergabe nach diesem Lied &stoppen - + &Show Track Page - + &Delete Item Element &entfernen - + &Show Album Page - + &Show Artist Page @@ -2053,12 +2045,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Lade %1 aus der Datenbank - + Parsing %1 %2 Parse %1 %2 @@ -2800,38 +2812,48 @@ Tomahawk auf Twitter's Website authentifiziert hast: TomahawkTrayIcon - + &Stop Playback after current Track Wiedergabe nach diesem Lied &stoppen - - + + Hide Tomahawk Window Tomahawk verbergen - + Show Tomahawk Window Tomahawk anzeigen - + Currently not playing. Derzeit wird nichts gespielt. - + Play Abspielen - + Pause Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track Wiedergabe nach diesem Lied &fortsetzen @@ -2975,7 +2997,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: - + Play Abspielen @@ -2995,167 +3017,167 @@ Tomahawk auf Twitter's Website authentifiziert hast: Weiter - + Back Zurück - + Go back one page Gehe eine Seite zurück - + Forward Vorwärts - + Go forward one page Gehe eine Seite vorwärts - + Global Search... Globale Suche... - - + + Check For Updates... Nach Updates suchen... - - - + + + Connect To Peer Mit anderem Tomahawk verbinden - + Enter peer address: Gib die Adresse der Gegenstelle ein: - + Enter peer port: Gib den Port der Gegenstelle ein: - + Enter peer key: Gib den Schlüssel der Gegenstelle ein: - + XSPF Error XSPF-Fehler - + This is not a valid XSPF playlist. Dies ist keine gültige XSPF-Playliste. - + Failed to save tracks Konnte Stücke nicht abspeichern - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Einige Stücke in der Playliste enthalten weder Künstler noch Titel. Diese werden ignoriert. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. Vergewisser dich, dass ein geignetes Phonon-Backend mitsamt benötigten Plugins installiert ist. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. - + Create New Station Neue Station erstellen - + Name: Name: - + New Station Neue Station - + New Playlist Neue Playliste - + Pause Pause - + Go &offline Verbindung &trennen - + Go &online &Verbindung herstellen - + Authentication Error Authentifizierungsfehler - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 von %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Über Tomahawk @@ -3759,107 +3781,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Nutzer Interaktion - + Host is unknown Host ist unbekannt - + Item not found Eintrag nicht gefunden - + Authorization Error Authentifizierungs Fehler - + Remote Stream Error - + Remote Connection failed - + Internal Server Error Interner Server Fehler - + System shutdown - + Conflict Konflikt - + Unknown Unbekannt - + No Compression Support Keine Kompressions Option - + No Encryption Support Keine Verschluesselungs Option - + No Authorization Support Keine Authorisierungs Option - + No Supported Feature Keine unterstuetzte Faehigkeit - + Add Friend Freund hinzufügen... - + Enter Xmpp ID: XMPP-Benutzer: - + Add Friend... Freund hinzufügen... - + XML Console... XML-Konsole... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorisiere Nutzer - + Do you want to grant <b>%1</b> access to your Collection? Willst du <b>%1</b> Zugriff auf deine Sammlung gewähren? diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index e524091ae..3056872fd 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -473,14 +473,6 @@ connect and stream from you? Copy to Clipboard - - DropJob - - - No tracks found for given %1 - No tracks found for given %1 - - GlobalSearchWidget @@ -972,12 +964,12 @@ connect and stream from you? - + Show Queue Show Queue - + Hide Queue Hide Queue @@ -1298,38 +1290,38 @@ connect and stream from you? &Export Playlist - + playlist playlist - + automatic playlist automatic playlist - + station station - + Delete %1? playlist/station/... Delete %1? - + Would you like to delete the %1 <b>"%2"</b>? Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -1610,32 +1602,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Add Account - + Remove Account Remove Account - + %1 downloads %1 downloads - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -1966,29 +1958,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Add to &Queue - + &Love &Love - + &Copy Track Link &Copy Track Link - + Un-&Love Un-&Love - + &Delete Items &Delete Items @@ -2003,22 +1995,22 @@ You may wish to try re-authenticating. &Stop Playback after this Track - + &Show Track Page &Show Track Page - + &Delete Item &Delete Item - + &Show Album Page &Show Album Page - + &Show Artist Page &Show Artist Page @@ -2059,12 +2051,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + playlist + + + + artist + artist + + + + track + track + + + + album + album + + + Fetching %1 from database Fetching %1 from database - + Parsing %1 %2 Parsing %1 %2 @@ -2806,38 +2818,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &Stop Playback after current Track - - + + Hide Tomahawk Window Hide Tomahawk Window - + Show Tomahawk Window Show Tomahawk Window - + Currently not playing. Currently not playing. - + Play Play - + Pause Pause - + + &Love + &Love + + + + Un-&Love + Un-&Love + + + &Continue Playback after current Track &Continue Playback after current Track @@ -2981,7 +3003,7 @@ enter the displayed PIN number here: - + Play Play @@ -3001,167 +3023,167 @@ enter the displayed PIN number here: Next - + Back Back - + Go back one page Go back one page - + Forward Forward - + Go forward one page Go forward one page - + Global Search... Global Search... - - + + Check For Updates... Check For Updates... - - - + + + Connect To Peer Connect To Peer - + Enter peer address: Enter peer address: - + Enter peer port: Enter peer port: - + Enter peer key: Enter peer key: - + XSPF Error XSPF Error - + This is not a valid XSPF playlist. This is not a valid XSPF playlist. - + Failed to save tracks Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Create New Station - + Name: Name: - + New Station New Station - + New Playlist New Playlist - + Pause Pause - + Go &offline Go &offline - + Go &online Go &online - + Authentication Error Authentication Error - + Error connecting to SIP: Authentication failed! Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Copyright 2010 - 2012 - + Thanks to: Thanks to: - + About Tomahawk About Tomahawk @@ -3775,107 +3797,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction User Interaction - + Host is unknown Host is unknown - + Item not found Item not found - + Authorization Error Authorization Error - + Remote Stream Error Remote Stream Error - + Remote Connection failed Remote Connection failed - + Internal Server Error Internal Server Error - + System shutdown System shutdown - + Conflict Conflict - + Unknown Unknown - + No Compression Support No Compression Support - + No Encryption Support No Encryption Support - + No Authorization Support No Authorization Support - + No Supported Feature No Supported Feature - + Add Friend Add Friend - + Enter Xmpp ID: Enter Xmpp ID: - + Add Friend... Add Friend... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Authorize User - + Do you want to grant <b>%1</b> access to your Collection? Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index b720e24ef..8cceabdff 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -472,14 +472,6 @@ connect and stream from you? Copiar al portapapeles - - DropJob - - - No tracks found for given %1 - Ninguna pista fue encontrada para %1 - - GlobalSearchWidget @@ -970,12 +962,12 @@ connect and stream from you? - + Show Queue Mostrar cola - + Hide Queue Ocultar cola @@ -1296,38 +1288,38 @@ connect and stream from you? &Exportar lista de reproducción - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -1608,32 +1600,32 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountDelegate - + Add Account Añadir Cuenta - + Remove Account Eliminar Cuenta - + %1 downloads %1 descargas - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -1964,29 +1956,29 @@ Hay que volverse a autenticar. - - + + Add to &Queue Añadir a la &cola - + &Love &Favorito - + &Copy Track Link &Copiar enlace del Tema - + Un-&Love Quitar de &Favoritos - + &Delete Items &Eliminar de la cola @@ -2001,22 +1993,22 @@ Hay que volverse a autenticar. &Para la Reproducción después de este Tema - + &Show Track Page - + &Delete Item &Eliminar de la cola - + &Show Album Page - + &Show Artist Page @@ -2057,12 +2049,32 @@ Hay que volverse a autenticar. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Obteniendo %1 de la base de datos - + Parsing %1 %2 Analizando %1 %2 @@ -2804,38 +2816,48 @@ introduzca su número PIN aquí: TomahawkTrayIcon - + &Stop Playback after current Track &Para la Reproducción después de este Tema - - + + Hide Tomahawk Window Ocultar ventana de Tomahawk - + Show Tomahawk Window Mostrar ventana de Tomahawk - + Currently not playing. Ninguna pista en reproducción. - + Play Reproducir - + Pause Pausar - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Continuar la Reproducción después de este Tema @@ -2979,7 +3001,7 @@ introduzca su número PIN aquí: - + Play Reproducir @@ -2999,167 +3021,167 @@ introduzca su número PIN aquí: Siguiente - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Búsqueda global... - - + + Check For Updates... Buscar actualizaciones... - - - + + + Connect To Peer Conectar a un par - + Enter peer address: Introducir dirección del par: - + Enter peer port: Introducir puerto del par: - + Enter peer key: Introducir contraseña del par: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. Esta no es una lista de reproducción XSPF válida. - + Failed to save tracks Fallo al guardar pistas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunas pistas en la lista de reproducción no contienen artista ni título. Serán ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. Asegúrese de que ha instalado un backend de Phonon adecuado y los plugins necesarios. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. - + Create New Station Crear nueva estación - + Name: Nombre: - + New Station Nueva estación - + New Playlist Nueva lista de reproducción - + Pause Pausar - + Go &offline &Desconectarse - + Go &online &Conectarse - + Authentication Error Error de autenticación - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 por %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Acerca de Tomahawk @@ -3772,107 +3794,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction Interacción de usuario - + Host is unknown Máquina desconocida - + Item not found Elemento no encontrado - + Authorization Error Error de Autorización - + Remote Stream Error Error de Stream Remoto - + Remote Connection failed Fallo en la Conexión Remota - + Internal Server Error Error de Servidor Interno - + System shutdown Sistema apagado - + Conflict Conflicto - + Unknown Desconocido - + No Compression Support Compresión no sportada - + No Encryption Support Encriptación no soportada - + No Authorization Support Autorización no soportada - + No Supported Feature Característica no soportada - + Add Friend Añadir Amigo - + Enter Xmpp ID: Introducir ID XMPP: - + Add Friend... Añadir Amigo... - + XML Console... Consola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Lo siento -- soy una presencia automática usada por el Reproductor Tomahawk (http://gettomahawk.com). Si recibe este mensaje, la persona con quién intenta contactar no esté contectada probablemente. Inténtelo más tarde! - + Authorize User Autorizar Usuario - + Do you want to grant <b>%1</b> access to your Collection? ¿Quiere permitir que <b>%1</b> acceda a su Colección? diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index cc9a6ef86..2c45a7cf0 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -473,14 +473,6 @@ se connecter et streamer depuis chez vous ? Copier dans le presse papier - - DropJob - - - No tracks found for given %1 - Aucune piste trouvée pour %1 - - GlobalSearchWidget @@ -972,12 +964,12 @@ se connecter et streamer depuis chez vous ? - + Show Queue Afficher la file d'attente - + Hide Queue Masquer la file d'attente @@ -1298,38 +1290,38 @@ se connecter et streamer depuis chez vous ? &Exporter la liste de lecture - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -1610,32 +1602,32 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::AccountDelegate - + Add Account Ajouter un compte - + Remove Account Supprimer le compte - + %1 downloads %1 téléchargements - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -1966,29 +1958,29 @@ Essayez de vous authentifier de nouveau. - - + + Add to &Queue &Ajouter à la file d'attente - + &Love &Favori - + &Copy Track Link &Copier le lien de la piste - + Un-&Love Supprimer des Favoris - + &Delete Items &Supprimer les éléments @@ -2003,22 +1995,22 @@ Essayez de vous authentifier de nouveau. &Stopper la lecture après cette piste - + &Show Track Page &Afficher la page de la piste - + &Delete Item &Supprimer l'élément - + &Show Album Page &Afficher la page de l'album - + &Show Artist Page &Afficher la page artiste @@ -2059,12 +2051,32 @@ Essayez de vous authentifier de nouveau. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Chargement de %1 depuis la base de données - + Parsing %1 %2 Décodage %1 %2 @@ -2806,38 +2818,48 @@ saisissez le numéro PIN ici : TomahawkTrayIcon - + &Stop Playback after current Track &Stopper la lecture après cette piste - - + + Hide Tomahawk Window Masquer la fenêtre Tomahawk - + Show Tomahawk Window Afficher la fenêtre Tomahawk - + Currently not playing. Pas de lecture en cours - + Play Lecture - + Pause Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Continuer la lecture après cette piste @@ -2981,7 +3003,7 @@ saisissez le numéro PIN ici : - + Play Lecture @@ -3001,167 +3023,167 @@ saisissez le numéro PIN ici : Suivant - + Back Retour - + Go back one page Reculer d'une page - + Forward Avancer - + Go forward one page Avancer d'une page - + Global Search... Recherche Globale... - - + + Check For Updates... Rechercher une mise à jour... - - - + + + Connect To Peer Connexion à un pair - + Enter peer address: Adresse du pair : - + Enter peer port: Port du pair : - + Enter peer key: Clé du pair : - + XSPF Error Erreur XSPF - + This is not a valid XSPF playlist. Ceci n'est pas une liste de lecture XSPF valide. - + Failed to save tracks Échec de la sauvegarde des pistes - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. - + Create New Station Créer une nouvelle station - + Name: Nom : - + New Station Nouvelle station - + New Playlist Nouvelle liste de lecture - + Pause Pause - + Go &offline Se &déconnecter - + Go &online Se c&onnecter - + Authentication Error Erreur d'authentification - + Error connecting to SIP: Authentication failed! Erreur de connexion SIP : échec de l'authentification ! - + %1 by %2 track, artist name %1 par %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk A propos de Tomahawk @@ -3775,107 +3797,107 @@ Paroles de "%1" par %2 : XmppSipPlugin - + User Interaction Interaction utilisateur - + Host is unknown L'hôte est inconnu - + Item not found Objet non trouvé - + Authorization Error Erreur d'autorisation - + Remote Stream Error Erreur de lecture à distance - + Remote Connection failed Erreur de connexion à distance - + Internal Server Error Erreur interne du serveur - + System shutdown Arrêt du système - + Conflict Conflit - + Unknown Ajouter un &ami... - + No Compression Support Pas de support de la compression - + No Encryption Support Pas de support du chiffrement - + No Authorization Support Pas de support de l'authorization - + No Supported Feature Fonctionnalité non supportée - + Add Friend Ajouter un ami - + Enter Xmpp ID: Entrer l'ID XMPP - + Add Friend... Ajouter un ami... - + XML Console... Console XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! Désolé -- Je suis une présence automatique utilisé par le lecteur Tomahawk (http://gettomahawk.com). Si vous lisez ce message, la personne que vous essayez de joindre n'est probablement pas connecter, donc essayez plus tard ! Merci ! - + Authorize User Autoriser l'utilisateur - + Do you want to grant <b>%1</b> access to your Collection? Voulez vous donner accès à votre collection à %1 ? diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 6a48bd4d9..3a3f12bab 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -472,14 +472,6 @@ connect and stream from you? クリップボードにコピーする - - DropJob - - - No tracks found for given %1 - %1 に該当するトラックは見つかりませんでした。 - - GlobalSearchWidget @@ -907,7 +899,8 @@ other: %n週間前 %n week(s) - + one: %n週間 +other: %n週間 @@ -977,12 +970,12 @@ other: %n週間前 - + Show Queue - + Hide Queue @@ -1303,38 +1296,38 @@ other: %n週間前 - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -1612,32 +1605,32 @@ other: %n週間前 Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1965,29 +1958,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue - + &Love &Love - + &Copy Track Link - + Un-&Love Loveじゃないトラック - + &Delete Items 項目を削除 @@ -2002,22 +1995,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item 項目を削除 - + &Show Album Page - + &Show Artist Page @@ -2058,12 +2051,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -2800,38 +2813,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Tomahawkのウインドウを隠す - + Show Tomahawk Window Tomahawkのウインドウを表示 - + Currently not playing. - + Play 再生 - + Pause 一時停止 - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2975,7 +2998,7 @@ enter the displayed PIN number here: - + Play @@ -2995,167 +3018,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station 新規ステーションを作成 - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3754,107 +3777,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 9472b83e6..e6c330bcc 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -472,14 +472,6 @@ connect and stream from you? Skopiuj do schowka - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget @@ -970,12 +962,12 @@ connect and stream from you? - + Show Queue Pokaż Kolejkę - + Hide Queue Ukryj Kolejkę @@ -1296,38 +1288,38 @@ connect and stream from you? &Eksportuj Listę - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -1609,32 +1601,32 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountDelegate - + Add Account Dodaj Konto - + Remove Account Usuń Konto - + %1 downloads pobrań: %1 - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -1962,29 +1954,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Dodaj do &kolejki - + &Love &Uwielbiam - + &Copy Track Link - + Un-&Love - + &Delete Items &Usuń pozycje @@ -1999,22 +1991,22 @@ You may wish to try re-authenticating. &Zatrzymaj odtwarzanie po tym utworze - + &Show Track Page - + &Delete Item &Usuń pozycję - + &Show Album Page - + &Show Artist Page @@ -2055,12 +2047,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Wydobywanie %1 z bazy danych - + Parsing %1 %2 Analizowanie %1 %2 @@ -2800,38 +2812,48 @@ wprowadź pokazany numer PIN tutaj: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Ukryj Okno Tomahawka - + Show Tomahawk Window Pokaż Okno Tomahawka - + Currently not playing. Aktualnie nie odtwarza. - + Play Odtwarzaj - + Pause Pauza - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2975,7 +2997,7 @@ wprowadź pokazany numer PIN tutaj: - + Play Odtwarzaj @@ -2995,167 +3017,167 @@ wprowadź pokazany numer PIN tutaj: Następny - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Globalne Wyszukiwanie... - - + + Check For Updates... Sprawdź uaktualnienia... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error Błąd XSPF - + This is not a valid XSPF playlist. To nie jest poprawna lista XSPF. - + Failed to save tracks Nie udało się zapisać utworów - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Niektóre utwory na liście nie zawierają artysty i tytułu. Zostaną one zignorowane. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Utwórz Nową Stację - + Name: Nazwa: - + New Station Nowa stacja - + New Playlist Nowa Lista - + Pause Pauza - + Go &offline Przejdź do trybu &offline - + Go &online Przejdź do trybu &online - + Authentication Error Błąd uwierzytelniania - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 wykonawcy %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3765,107 +3787,107 @@ Tekst dla "%1" wykonawcy %2: XmppSipPlugin - + User Interaction - + Host is unknown Nieznany Host - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed Połączenie sieciowe się nie powiodło - + Internal Server Error Wewnętrzny błąd serwera - + System shutdown Wyłączenie systemu - + Conflict Konflikt - + Unknown Nieznany - + No Compression Support Brak obsługi kompresji - + No Encryption Support Brak obsługi szyfrowania - + No Authorization Support Brak obsługi autoryzacji - + No Supported Feature Brak obsługi danej funkcji - + Add Friend Dodaj Znajomego - + Enter Xmpp ID: - + Add Friend... Dodaj Znajomego... - + XML Console... Konsola XML... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Autoryzuj Użytkownika - + Do you want to grant <b>%1</b> access to your Collection? Czy chcesz udzielić dostępu do swojej kolekcji <b>%1</b>? diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 929440cd9..9bdb318ba 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -472,14 +472,6 @@ connect and stream from you? Copiar - - DropJob - - - No tracks found for given %1 - Nenhuma faixa encontrada para %1 - - GlobalSearchWidget @@ -970,12 +962,12 @@ connect and stream from you? - + Show Queue Mostrar fila - + Hide Queue Ocultar fila @@ -1296,38 +1288,38 @@ connect and stream from you? &Exportar lista de reprodução - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -1608,32 +1600,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Adicionar Conta - + Remove Account Remover Conta - + %1 downloads - + Online - + Connecting... Conectando... - + Offline @@ -1961,29 +1953,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Adicionar à &lista - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items &Eliminar itens @@ -1998,22 +1990,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item &Eliminar item - + &Show Album Page - + &Show Artist Page @@ -2054,12 +2046,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Buscando %1 na base de dados - + Parsing %1 %2 Analisando %1 %2 @@ -2799,38 +2811,48 @@ colocar o número PIN mostrado aqui: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Esconder janela do Tomahawk - + Show Tomahawk Window Mostrar janela do Tomahawk - + Currently not playing. Não reproduzindo nada. - + Play Reporduzir - + Pause Pausar - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2974,7 +2996,7 @@ colocar o número PIN mostrado aqui: - + Play Reporduzir @@ -2994,167 +3016,167 @@ colocar o número PIN mostrado aqui: Próximo - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Busca global... - - + + Check For Updates... Buscar atualizações... - - - + + + Connect To Peer Conectar-se ao par - + Enter peer address: Coloque o endereço do par: - + Enter peer port: Coloque a porta do par: - + Enter peer key: Coloque a chave do par: - + XSPF Error Erro de XSPF - + This is not a valid XSPF playlist. Esta não é uma lista de reprodução XSPF válida. - + Failed to save tracks Falha ao salvar faixas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algumas faixas da lista de reprodução não contem artista e título. Estas serão ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Criar uma nova estação - + Name: Nome: - + New Station Nova estação - + New Playlist Nova lista de reprodução - + Pause Pausar - + Go &offline Desc&onectar - + Go &online C&onectar - + Authentication Error Erro de autenticação - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Sobre o Tomahawk @@ -3765,107 +3787,107 @@ Letras de "%1" por %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found Item não encontrado - + Authorization Error - + Remote Stream Error - + Remote Connection failed Conexão Remota falhou - + Internal Server Error - + System shutdown - + Conflict - + Unknown Desconhecido - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend Adicionar Amigo - + Enter Xmpp ID: - + Add Friend... Adicionar Amigo... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Autorizar Usuário - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index a89afa615..9edb57e90 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -473,14 +473,6 @@ connect and stream from you? Сохранить в буфер обмена - - DropJob - - - No tracks found for given %1 - Не найдено песен по %1 - - GlobalSearchWidget @@ -972,12 +964,12 @@ connect and stream from you? - + Show Queue Показать Очередь - + Hide Queue Скрыть Очередь @@ -1298,38 +1290,38 @@ connect and stream from you? &Экспорт Плейлиста - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -1607,32 +1599,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Добавить аккаунт - + Remove Account Удалить аккаунт - + %1 downloads %1 загружено - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -1963,29 +1955,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Добавить В &Очередь - + &Love &Любимая - + &Copy Track Link &Скопировать Ссылку Песни - + Un-&Love &Не Любимая - + &Delete Items &Удалить Песни @@ -2000,22 +1992,22 @@ You may wish to try re-authenticating. &Остановить воспроизведения и после этого трека - + &Show Track Page - + &Delete Item &Удалить Песню - + &Show Album Page - + &Show Artist Page @@ -2056,12 +2048,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Выборка %1 из базы данных - + Parsing %1 %2 Анализирую %1 %2 @@ -2800,38 +2812,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track &Остановить после текущего трека - - + + Hide Tomahawk Window Спрятать окно Tomahawk - + Show Tomahawk Window Показать окно Tomahawk - + Currently not playing. Не воспроизводится. - + Play Играть - + Pause Пауза - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track &Продолжить воспроизведение после текущего трека @@ -2975,7 +2997,7 @@ enter the displayed PIN number here: - + Play Играть @@ -2995,167 +3017,167 @@ enter the displayed PIN number here: Следующая - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Глобальный поиск - - + + Check For Updates... Проверить обновления... - - - + + + Connect To Peer Связаться с Peer - + Enter peer address: Введите адрес узла: - + Enter peer port: Введите адрес порта: - + Enter peer key: Введите адрес ключа: - + XSPF Error Ошибка XSPF - + This is not a valid XSPF playlist. Это не является допустимым XSPF плейлистом. - + Failed to save tracks Не удалось сохранить песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Некоторые треки в плейлисте не содержат исполнителя и название. Они будут проигнорированы. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Создать новую станцию - + Name: Имя: - + New Station Новая станция - + New Playlist Новый плейлист - + Pause Пауза - + Go &offline Отключиться - + Go &online Подлючиться - + Authentication Error Ошибка авторизации - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk О Tomahawk @@ -3764,107 +3786,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction Взаимодействие с пользователем - + Host is unknown Неизвестный хост - + Item not found Песня не найдена - + Authorization Error Ошибка авторизации - + Remote Stream Error Удаленный поток ошибок - + Remote Connection failed Ошибка подключения - + Internal Server Error Внутренняя ошибка сервера - + System shutdown Выключение системы - + Conflict Конфликт - + Unknown Неизвестный - + No Compression Support Нет поддержки сжатия - + No Encryption Support Нет поддержки шифрования - + No Authorization Support Нет поддержки авторизации - + No Supported Feature Не поддерживаемые функции - + Add Friend Добавить друга - + Enter Xmpp ID: Введите XMPP ID: - + Add Friend... Добавить друга... - + XML Console... XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User Авторизация пользователя - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 0d2cfeec2..557733c91 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -472,14 +472,6 @@ connect and stream from you? Kopiera till urklipp - - DropJob - - - No tracks found for given %1 - Inga låtar hittades för %1 - - GlobalSearchWidget @@ -971,12 +963,12 @@ connect and stream from you? - + Show Queue Visa kö - + Hide Queue Dölj kö @@ -1297,38 +1289,38 @@ connect and stream from you? &Exportera spellista - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -1606,32 +1598,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1959,29 +1951,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue Lägg till i &kö - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items &Ta bort objekt @@ -1996,22 +1988,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item &Ta bort objekt - + &Show Album Page - + &Show Artist Page @@ -2052,12 +2044,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database Hämtar %1 från databasen - + Parsing %1 %2 Tolkar %1 %2 @@ -2794,38 +2806,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window Dölj Tomahawk-fönstret - + Show Tomahawk Window Visa Tomahawk-fönstret - + Currently not playing. Spelar ingenting för närvarande. - + Play Spela upp - + Pause Paus - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2969,7 +2991,7 @@ enter the displayed PIN number here: - + Play Spela upp @@ -2989,167 +3011,167 @@ enter the displayed PIN number here: Nästa - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Global sökning... - - + + Check For Updates... Leta efter uppdateringar... - - - + + + Connect To Peer Anslut till klient - + Enter peer address: Ange klientadress: - + Enter peer port: Ange klientport: - + Enter peer key: Ange klientnyckel: - + XSPF Error XSPF-fel - + This is not a valid XSPF playlist. Detta är inte en giltig XSPF-spellista. - + Failed to save tracks Misslyckades med att spara spår - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Några spår i spellistan innehåller inte någon artist och titel. De kommer att ignoreras. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station Skapa ny station - + Name: Namn: - + New Station Ny station - + New Playlist Ny spellista - + Pause Paus - + Go &offline Koppla &från - + Go &online A&nslut - + Authentication Error Autentiseringsfel - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 av %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3748,107 +3770,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 968726d82..2d019547d 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -472,14 +472,6 @@ connect and stream from you? Pano'ya Kopyala - - DropJob - - - No tracks found for given %1 - Verilen %1 için hiç parça bulunamadı. - - GlobalSearchWidget @@ -970,12 +962,12 @@ connect and stream from you? - + Show Queue - + Hide Queue @@ -1296,38 +1288,38 @@ connect and stream from you? - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF - + Playlists (*.xspf) @@ -1605,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1958,29 +1950,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items @@ -1995,22 +1987,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item - + &Show Album Page - + &Show Artist Page @@ -2051,12 +2043,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -2793,38 +2805,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2968,7 +2990,7 @@ enter the displayed PIN number here: - + Play @@ -2988,167 +3010,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3747,107 +3769,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 0ac831b28..98ab5ee42 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -472,14 +472,6 @@ connect and stream from you? 复制到剪贴板 - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget @@ -970,12 +962,12 @@ connect and stream from you? - + Show Queue - + Hide Queue @@ -1296,38 +1288,38 @@ connect and stream from you? - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF - + Playlists (*.xspf) @@ -1605,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1958,29 +1950,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items @@ -1995,22 +1987,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item - + &Show Album Page - + &Show Artist Page @@ -2051,12 +2043,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -2793,38 +2805,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2968,7 +2990,7 @@ enter the displayed PIN number here: - + Play @@ -2988,167 +3010,167 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3747,107 +3769,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction - + Host is unknown - + Item not found - + Authorization Error - + Remote Stream Error - + Remote Connection failed - + Internal Server Error - + System shutdown - + Conflict - + Unknown - + No Compression Support - + No Encryption Support - + No Authorization Support - + No Supported Feature - + Add Friend - + Enter Xmpp ID: - + Add Friend... - + XML Console... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User - + Do you want to grant <b>%1</b> access to your Collection? diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 2096a8210..9640610ba 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -472,14 +472,6 @@ connect and stream from you? 複製到剪貼簿 - - DropJob - - - No tracks found for given %1 - - - GlobalSearchWidget @@ -970,12 +962,12 @@ connect and stream from you? - + Show Queue 顯示佇列 - + Hide Queue 隱藏佇列 @@ -1296,38 +1288,38 @@ connect and stream from you? 匯出播放清單 - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -1605,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account 新增帳戶 - + Remove Account 刪除帳戶 - + %1 downloads - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -1958,29 +1950,29 @@ You may wish to try re-authenticating. - - + + Add to &Queue 添加至佇列 - + &Love - + &Copy Track Link - + Un-&Love - + &Delete Items @@ -1995,22 +1987,22 @@ You may wish to try re-authenticating. - + &Show Track Page - + &Delete Item - + &Show Album Page - + &Show Artist Page @@ -2051,12 +2043,32 @@ You may wish to try re-authenticating. Tomahawk::DropJobNotifier - + + playlist + + + + + artist + + + + + track + + + + + album + + + + Fetching %1 from database - + Parsing %1 %2 @@ -2793,38 +2805,48 @@ enter the displayed PIN number here: TomahawkTrayIcon - + &Stop Playback after current Track - - + + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. 目前沒有播放。 - + Play 播放 - + Pause 暫停 - + + &Love + + + + + Un-&Love + + + + &Continue Playback after current Track @@ -2968,7 +2990,7 @@ enter the displayed PIN number here: - + Play 播放 @@ -2988,167 +3010,167 @@ enter the displayed PIN number here: 下一首 - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... 全域搜尋... - - + + Check For Updates... 檢查更新... - - - + + + Connect To Peer 連接點對點 - + Enter peer address: 輸入對等地址: - + Enter peer port: 輸入對等連接埠: - + Enter peer key: 輸入對等密鑰: - + XSPF Error XSPF 錯誤 - + This is not a valid XSPF playlist. - + Failed to save tracks 無法儲存曲目 - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Create New Station - + Name: 名稱: - + New Station - + New Playlist 新增播放清單 - + Pause 暫停 - + Go &offline 離線 - + Go &online 上網 - + Authentication Error 驗證錯誤 - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3748,107 +3770,107 @@ Lyrics for "%1" by %2: XmppSipPlugin - + User Interaction 使用者互動 - + Host is unknown 主機是未知 - + Item not found - + Authorization Error 授權錯誤 - + Remote Stream Error 遠端串流錯誤 - + Remote Connection failed 遠端連線失敗 - + Internal Server Error 內部服務器錯誤 - + System shutdown 系統關閉 - + Conflict 衝突 - + Unknown 未知 - + No Compression Support 沒有壓縮支持 - + No Encryption Support 沒有加密支持 - + No Authorization Support 沒有授權支持 - + No Supported Feature 沒有支持的功能 - + Add Friend 加為好友 - + Enter Xmpp ID: 輸入XMPP識別碼: - + Add Friend... 加為好友... - + XML Console... XML的控制台... - + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - + Authorize User 授權用戶 - + Do you want to grant <b>%1</b> access to your Collection? From 4082395d4b532c07038d432e048de35a9ad8018d Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Tue, 29 May 2012 10:18:40 -0400 Subject: [PATCH 149/433] Change track temp page icon in sidebar to same style as others --- data/images/track-icon-sidebar.png | Bin 0 -> 5264 bytes data/images/track-placeholder.png | Bin 1054090 -> 69076 bytes resources.qrc | 3 ++- src/sourcetree/items/TemporaryPageItem.cpp | 2 +- 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 data/images/track-icon-sidebar.png diff --git a/data/images/track-icon-sidebar.png b/data/images/track-icon-sidebar.png new file mode 100644 index 0000000000000000000000000000000000000000..b579f957cf8815f8da5a3f4d4a64e03daed47f18 GIT binary patch literal 5264 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 Q%*X0r|7m`8J_&375Ax=zIRF3v literal 0 HcmV?d00001 diff --git a/data/images/track-placeholder.png b/data/images/track-placeholder.png index 2851e5b3f3bf35a2827a444e8b73f8b47ba9e406..333ea9101e75ba2d9edc10fbf10247b7289b9f1a 100644 GIT binary patch delta 4776 zcmbuD4{TLe9mntKd+>mj{(*wUb+jyWRtIe{bk+&B#SUn@@<+wC@$)_R-q%;k786h2 zx#!(;zQ6D9&-tBm?!C`+R{!DW(MdmEFmKN2QJ){>dEV%{xwYS6}X)03ICUfX0~Kj3I+vSz?=M_W(%!%&4FQe!6h^Dfm(wC54$mN( zG@jYVz(K-#+4XWEP#v%=mF%-o#jUIPY`LjPBM`GQYA;$kme-fQ5(=x;464xYTJ9A@ zn_zl2V@!#epT_0PzJjsO13tLCzU-J23NGRbdBQf;XT8(-G1Ynb48#Ry>CMFNF5F8Ydrfr z;#Wetl)a9&EFS+-G?R)FwCwfo{p(N{u0wDrR!85V~CBD*lVmn77?+}BUb;=Xgbd7EeF^hQP^2mOFgk)_iKU0B?7yjRq>9C1Lw!inI#CK1b1<~Uht6Gz5E6jBh zVVaX`XL1BZFj@aH+$mXYI8aXX6h^0;JDl-;B7t@ZWp!*t3C|do#BYF=nDUg5F55i2 z$69lQ(|pj5AdiWxAzmo>6_S&kB($1V>$M{BWLjLj4)*_LgZFUlEW*(JDz9~XPPDq`%ga!T$w!CX0Tz2KQRGJ9atrEyH1-^j8+i?Io2ZLuu ziCkZZA8Yiy5zDf69NZTK^*Lt~>cc|ebB@W=YLXdcXir1c$EuEvZk5P|wOS)(N{ zzn^9S(}&|tSam=mg8D?Y#yvkxis3elZ{S-~4ntmhPv0;)mVtH%HzS*TD*6}k3~(US z=u_21iNL?4wK(P?ZO+5Cz=cjqQP7Kn&&k2oJoj)xR}*va@_;=J8Fptpe%EjatX+)! z{dvJ4M)xfzEVDw3wuxv1>8b3r-Zrdo7WvjR4rd-Ovhi__+?lO81vN!>zz1(l8gG9o z8$i2QWW6(RLk_liSC==GJ|-ETb76)b)w{CgA2JIE#%8+H7M%ENwa$dVUKy}crmoMC z&k}5wm~Y17VN6VpCcZcqLiKm|GkxLswDEFZC7^y3&LhT%^+lgm4~SQYVuz4{^I4%3 zXXFBxSH*eYWRJH74T}P{c)YkMgsQ8(r+-*`cmG=ecc7ET_jtEdJ)!jF0WcMgAbtBs z!aRv?yeMe|BPqKd-tUPsETNuT-G?~V!bZfe!7&}2n~x6nvHUsSA{WagjOQYN!a_d^L5d=>;zjzC^D2n zB z!dR~J2?$(-{qzPZEAvS{k5#2K=SZ}F5;?`aJ5OS5v$?tJR5QY9`D~w z;#Zi(cjED)Jgp#VccV{XAH!A~fH&)MQT}3UEO_I)` z9|S(T=Z7Zx!QFKy6Sgt3>3@-z;^7&_bTyy7WX5QV^1KW}(TgKmNAzDX{^u0p!@Dho zwdVV(n_w#Z?=E*bul#QRyNmmB!Zv`Q*{=cLW%B&R@ywJfeAeL$jr+@tcj+^bz6T`_ zRmX0`h{Og{kkh>C5`gXcg5(SNSJUckB&VOu>pQl3>%8+z7pc4MzInAT&wBW&{{o^4 Bc4Ghl literal 1054090 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 I>xirVA8h_3R{#J2 diff --git a/resources.qrc b/resources.qrc index bea3686be..05f94a4b9 100644 --- a/resources.qrc +++ b/resources.qrc @@ -141,6 +141,7 @@ data/images/process-stop.png data/icons/tomahawk-icon-128x128-grayscale.png data/images/collection.png - data/misc/tomahawk_pubkey.pem + data/misc/tomahawk_pubkey.pem + data/images/track-icon-sidebar.png diff --git a/src/sourcetree/items/TemporaryPageItem.cpp b/src/sourcetree/items/TemporaryPageItem.cpp index 4ad95a213..dc9f4a169 100644 --- a/src/sourcetree/items/TemporaryPageItem.cpp +++ b/src/sourcetree/items/TemporaryPageItem.cpp @@ -36,7 +36,7 @@ TemporaryPageItem::TemporaryPageItem ( SourcesModel* mdl, SourceTreeItem* parent else if ( dynamic_cast< AlbumInfoWidget* >( page ) ) m_icon = QIcon( RESPATH "images/album-icon.png" ); else if ( dynamic_cast< TrackInfoWidget* >( page ) ) - m_icon = QIcon( RESPATH "images/track-icon-22x22.png" ); + m_icon = QIcon( RESPATH "images/track-icon-sidebar.png" ); else if ( dynamic_cast< SearchWidget* >( page ) ) m_icon = QIcon( RESPATH "images/search-icon.png" ); From 7cebabf7f219f9ccbe9707b90a50e2d2c1ac3690 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Tue, 29 May 2012 14:31:46 -0400 Subject: [PATCH 150/433] Bigger SVG icon. See if this helps the Linux Mint implementation of Gnome3/icon --- data/icons/tomahawk-icon.svg | 84 +++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/data/icons/tomahawk-icon.svg b/data/icons/tomahawk-icon.svg index c36bc26f2..2feea87fb 100644 --- a/data/icons/tomahawk-icon.svg +++ b/data/icons/tomahawk-icon.svg @@ -1,21 +1,63 @@ - - - - - - - - - - - + + + +image/svg+xml + + + + + + + \ No newline at end of file From a3cfdae7e89c4136873e33e71ab3911007ea15f3 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Tue, 29 May 2012 15:08:41 -0400 Subject: [PATCH 151/433] Tweak SVG some more to see if it's better or worse --- data/icons/tomahawk-icon.svg | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/data/icons/tomahawk-icon.svg b/data/icons/tomahawk-icon.svg index 2feea87fb..6b45c0e9d 100644 --- a/data/icons/tomahawk-icon.svg +++ b/data/icons/tomahawk-icon.svg @@ -32,20 +32,33 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="640" - inkscape:window-height="480" + inkscape:window-width="1017" + inkscape:window-height="940" id="namedview11" showgrid="false" - inkscape:zoom="0.38247276" - inkscape:cx="420.94501" - inkscape:cy="297.64001" + inkscape:zoom="0.79203971" + inkscape:cx="431.12552" + inkscape:cy="295.63997" inkscape:window-x="258" inkscape:window-y="62" inkscape:window-maximized="0" - inkscape:current-layer="Layer_1" /> + inkscape:current-layer="Layer_1" + inkscape:snap-page="false"> + transform="matrix(7.3080643,0,0,7.1790074,-2773.1692,-1839.2291)"> Date: Tue, 29 May 2012 22:16:42 +0000 Subject: [PATCH 152/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 10 +++++----- lang/tomahawk_ja.ts | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 3ca6093af..693d49b9d 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -361,7 +361,7 @@ connect and stream from you? InfoBar - شريط المعلومات + InfoBar @@ -1619,7 +1619,7 @@ connect and stream from you? Online - على الهواء + متصل @@ -2909,7 +2909,7 @@ enter the displayed PIN number here: Go &Online - إذهب &على الهواء + اصبح &متصل @@ -3138,7 +3138,7 @@ enter the displayed PIN number here: Go &online - إذهب &على الهواء + اصبح &متصل @@ -3509,7 +3509,7 @@ You can re-send a sync message at any time simply by sending another tweet using Combined libraries of all your online friends - جمع مكاتب أصدقائك الذين على الهواء + مكتبات مجمعة لكل اصحابك المتصلين diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 3a3f12bab..d6c288d56 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -762,7 +762,7 @@ connect and stream from you? New Playlist - + 新規プレイリスト @@ -1126,17 +1126,17 @@ other: %n週間 Track - + トラック Album - + アルバム Artist - + アーティスト @@ -1151,7 +1151,7 @@ other: %n週間 Offline - + オフライン @@ -1161,7 +1161,7 @@ other: %n週間 Online - + オンライン @@ -1214,7 +1214,7 @@ other: %n週間 Collection - + コレクション @@ -1415,7 +1415,7 @@ other: %n週間 Form - + フォーム @@ -1607,12 +1607,12 @@ other: %n週間 Add Account - + アカウントを追加 Remove Account - + アカウントを削除 @@ -1622,7 +1622,7 @@ other: %n週間 Online - + オンライン @@ -1632,7 +1632,7 @@ other: %n週間 Offline - + ・オフライン From 5f385753c399f9b8a2510904f38592c3e613120f Mon Sep 17 00:00:00 2001 From: Lucas Lira Gomes Date: Tue, 29 May 2012 19:37:56 -0300 Subject: [PATCH 153/433] * Fixed FindJreen.cmake. --- CMakeModules/FindJreen.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeModules/FindJreen.cmake b/CMakeModules/FindJreen.cmake index 3788e9f23..e1f97d16c 100644 --- a/CMakeModules/FindJreen.cmake +++ b/CMakeModules/FindJreen.cmake @@ -30,7 +30,6 @@ ENDIF() INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jreen - REQUIRED_VARS JREEN_LIBRARIES JREEN_INCLUDE_DIR - VERSION_VAR PC_JREEN_VERSION) + REQUIRED_VARS JREEN_LIBRARIES JREEN_INCLUDE_DIR) MARK_AS_ADVANCED(JREEN_INCLUDE_DIR JREEN_LIBRARIES) From 2a5d061deef14b3c08fd8580db86c8277f359d76 Mon Sep 17 00:00:00 2001 From: Lucas Lira Gomes Date: Tue, 29 May 2012 19:39:21 -0300 Subject: [PATCH 154/433] * Made ZeroConfAccount less bug prone. --- src/accounts/zeroconf/ZeroconfAccount.cpp | 10 +++++----- src/accounts/zeroconf/ZeroconfAccount.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/accounts/zeroconf/ZeroconfAccount.cpp b/src/accounts/zeroconf/ZeroconfAccount.cpp index 44d74e057..364022a37 100644 --- a/src/accounts/zeroconf/ZeroconfAccount.cpp +++ b/src/accounts/zeroconf/ZeroconfAccount.cpp @@ -86,7 +86,7 @@ void ZeroconfAccount::authenticate() { if ( !isAuthenticated() ) - static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->connectPlugin(); + sipPlugin()->connectPlugin(); } @@ -94,7 +94,7 @@ void ZeroconfAccount::deauthenticate() { if ( isAuthenticated() ) - static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->disconnectPlugin(); + sipPlugin()->disconnectPlugin(); } @@ -112,7 +112,7 @@ ZeroconfAccount::connectionState() const return Disconnected; // TODO can we get called before sipPlugin()? - return static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->connectionState(); + return m_sipPlugin.data()->connectionState(); } @@ -120,10 +120,10 @@ SipPlugin* ZeroconfAccount::sipPlugin() { if ( m_sipPlugin.isNull() ) - m_sipPlugin = QWeakPointer< SipPlugin >( new ZeroconfPlugin( this ) ); + m_sipPlugin = QWeakPointer< ZeroconfPlugin >( new ZeroconfPlugin( this ) ); return m_sipPlugin.data(); } -Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::ZeroconfFactory ) \ No newline at end of file +Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::ZeroconfFactory ) diff --git a/src/accounts/zeroconf/ZeroconfAccount.h b/src/accounts/zeroconf/ZeroconfAccount.h index 30d43e038..136c971c0 100644 --- a/src/accounts/zeroconf/ZeroconfAccount.h +++ b/src/accounts/zeroconf/ZeroconfAccount.h @@ -19,6 +19,7 @@ #ifndef ZEROCONF_ACCOUNTS_H #define ZEROCONF_ACCOUNTS_H +#include "Zeroconf.h" #include "accounts/Account.h" #include "../AccountDllMacro.h" @@ -71,7 +72,7 @@ public: QWidget* aclWidget() { return 0; } private: - QWeakPointer< SipPlugin > m_sipPlugin; + QWeakPointer< ZeroconfPlugin > m_sipPlugin; }; } From 9fe91d6af10b96d3e7edd384900dff78942f05f3 Mon Sep 17 00:00:00 2001 From: Lucas Lira Gomes Date: Tue, 29 May 2012 19:40:17 -0300 Subject: [PATCH 155/433] * Moved some files to libtomahawk. --- src/CMakeLists.txt | 8 -------- src/SettingsDialog.cpp | 8 ++++---- src/libtomahawk/CMakeLists.txt | 6 ++++++ src/{ => libtomahawk/accounts}/AccountDelegate.cpp | 1 + src/{ => libtomahawk/accounts}/AccountDelegate.h | 3 ++- src/{ => libtomahawk/accounts}/AccountFactoryWrapper.cpp | 2 +- src/{ => libtomahawk/accounts}/AccountFactoryWrapper.h | 4 +++- src/{ => libtomahawk/accounts}/AccountFactoryWrapper.ui | 0 .../accounts}/AccountFactoryWrapperDelegate.cpp | 0 .../accounts}/AccountFactoryWrapperDelegate.h | 0 src/{ => libtomahawk/accounts}/DelegateConfigWrapper.cpp | 0 src/{ => libtomahawk/accounts}/DelegateConfigWrapper.h | 0 src/{ => libtomahawk}/utils/GuiHelpers.cpp | 4 ++-- src/{ => libtomahawk}/utils/GuiHelpers.h | 8 +++++--- 14 files changed, 24 insertions(+), 20 deletions(-) rename src/{ => libtomahawk/accounts}/AccountDelegate.cpp (99%) rename src/{ => libtomahawk/accounts}/AccountDelegate.h (97%) rename src/{ => libtomahawk/accounts}/AccountFactoryWrapper.cpp (99%) rename src/{ => libtomahawk/accounts}/AccountFactoryWrapper.h (95%) rename src/{ => libtomahawk/accounts}/AccountFactoryWrapper.ui (100%) rename src/{ => libtomahawk/accounts}/AccountFactoryWrapperDelegate.cpp (100%) rename src/{ => libtomahawk/accounts}/AccountFactoryWrapperDelegate.h (100%) rename src/{ => libtomahawk/accounts}/DelegateConfigWrapper.cpp (100%) rename src/{ => libtomahawk/accounts}/DelegateConfigWrapper.h (100%) rename src/{ => libtomahawk}/utils/GuiHelpers.cpp (98%) rename src/{ => libtomahawk}/utils/GuiHelpers.h (80%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07e594c76..61479c7c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,8 +68,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/items/GroupItem.cpp sourcetree/items/HistoryItem.cpp - utils/GuiHelpers.cpp - accounts/lastfm/LastFmAccount.cpp accounts/lastfm/LastFmConfig.cpp accounts/lastfm/LastFmInfoPlugin.cpp @@ -82,13 +80,9 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} AudioControls.cpp SettingsDialog.cpp DiagnosticsDialog.cpp - AccountDelegate.cpp SettingsListDelegate.cpp - DelegateConfigWrapper.cpp TomahawkWindow.cpp LoadXSPFDialog.cpp - AccountFactoryWrapper.cpp - AccountFactoryWrapperDelegate.cpp SocialWidget.cpp ) @@ -107,7 +101,6 @@ SET( tomahawkUI ${tomahawkUI} AudioControls.ui LoadXSPFDialog.ui - AccountFactoryWrapper.ui SocialWidget.ui ) @@ -122,7 +115,6 @@ INCLUDE_DIRECTORIES( network sourcetree topbar - utils libtomahawk mac diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index c9cc2546c..54fab5fa5 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -32,16 +32,16 @@ #include "AtticaManager.h" #include "TomahawkApp.h" #include "TomahawkSettings.h" -#include "DelegateConfigWrapper.h" +#include "accounts/DelegateConfigWrapper.h" #include "MusicScanner.h" #include "Pipeline.h" #include "Resolver.h" #include "ExternalResolverGui.h" #include "utils/TomahawkUtilsGui.h" -#include "GuiHelpers.h" +#include "utils/GuiHelpers.h" #include "ScanManager.h" #include "SettingsListDelegate.h" -#include "AccountDelegate.h" +#include "accounts/AccountDelegate.h" #include "database/Database.h" #include "network/Servent.h" #include "utils/AnimatedSpinner.h" @@ -51,7 +51,7 @@ #include #include #include "utils/Logger.h" -#include "AccountFactoryWrapper.h" +#include "accounts/AccountFactoryWrapper.h" #include "accounts/spotify/SpotifyAccount.h" #include "ui_ProxyDialog.h" diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 4a1f0c049..ab645e2cb 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -191,6 +191,10 @@ set( libSources accounts/AccountModel.cpp accounts/AccountModelFilterProxy.cpp accounts/ResolverAccount.cpp + accounts/AccountDelegate.cpp + accounts/DelegateConfigWrapper.cpp + accounts/AccountFactoryWrapper.cpp + accounts/AccountFactoryWrapperDelegate.cpp sip/SipPlugin.cpp sip/SipHandler.cpp sip/SipInfo.cpp @@ -288,6 +292,7 @@ set( libSources utils/Qnr_IoDeviceStream.cpp utils/XspfLoader.cpp utils/TomahawkCache.cpp + utils/GuiHelpers.cpp thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp @@ -311,6 +316,7 @@ set( libUI ${libUI} playlist/QueueView.ui context/ContextWidget.ui infobar/InfoBar.ui + accounts/AccountFactoryWrapper.ui ) include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. .. diff --git a/src/AccountDelegate.cpp b/src/libtomahawk/accounts/AccountDelegate.cpp similarity index 99% rename from src/AccountDelegate.cpp rename to src/libtomahawk/accounts/AccountDelegate.cpp index 7434fd826..a674d582b 100644 --- a/src/AccountDelegate.cpp +++ b/src/libtomahawk/accounts/AccountDelegate.cpp @@ -604,6 +604,7 @@ AccountDelegate::drawStatus( QPainter* painter, const QPointF& rightTopEdge, Acc { QPixmap p; QString statusText; + const Account::ConnectionState state = acct->connectionState(); if ( state == Account::Connected ) { diff --git a/src/AccountDelegate.h b/src/libtomahawk/accounts/AccountDelegate.h similarity index 97% rename from src/AccountDelegate.h rename to src/libtomahawk/accounts/AccountDelegate.h index 6fbcdffdb..1b70a7df6 100644 --- a/src/AccountDelegate.h +++ b/src/libtomahawk/accounts/AccountDelegate.h @@ -19,6 +19,7 @@ #ifndef ACCOUNTDELEGATE_H #define ACCOUNTDELEGATE_H +#include "DllMacro.h" #include #include "accounts/AccountModel.h" @@ -31,7 +32,7 @@ namespace Accounts class Account; -class AccountDelegate : public QStyledItemDelegate +class DLLEXPORT AccountDelegate : public QStyledItemDelegate { Q_OBJECT public: diff --git a/src/AccountFactoryWrapper.cpp b/src/libtomahawk/accounts/AccountFactoryWrapper.cpp similarity index 99% rename from src/AccountFactoryWrapper.cpp rename to src/libtomahawk/accounts/AccountFactoryWrapper.cpp index adf5cb41d..4b1214b1c 100644 --- a/src/AccountFactoryWrapper.cpp +++ b/src/libtomahawk/accounts/AccountFactoryWrapper.cpp @@ -20,7 +20,7 @@ #include "accounts/Account.h" #include "accounts/AccountManager.h" -#include "GuiHelpers.h" +#include "utils/GuiHelpers.h" #include "AccountFactoryWrapperDelegate.h" #include "DelegateConfigWrapper.h" #include "ui_AccountFactoryWrapper.h" diff --git a/src/AccountFactoryWrapper.h b/src/libtomahawk/accounts/AccountFactoryWrapper.h similarity index 95% rename from src/AccountFactoryWrapper.h rename to src/libtomahawk/accounts/AccountFactoryWrapper.h index 00e31e672..ac8bf195d 100644 --- a/src/AccountFactoryWrapper.h +++ b/src/libtomahawk/accounts/AccountFactoryWrapper.h @@ -19,6 +19,8 @@ #ifndef ACCOUNTFACTORYWRAPPER_H #define ACCOUNTFACTORYWRAPPER_H +#include "DllMacro.h" + #include #include @@ -33,7 +35,7 @@ class Account; class Ui_AccountFactoryWrapper; // class AccountFactoryWrapper_ -class AccountFactoryWrapper : public QDialog +class DLLEXPORT AccountFactoryWrapper : public QDialog { Q_OBJECT public: diff --git a/src/AccountFactoryWrapper.ui b/src/libtomahawk/accounts/AccountFactoryWrapper.ui similarity index 100% rename from src/AccountFactoryWrapper.ui rename to src/libtomahawk/accounts/AccountFactoryWrapper.ui diff --git a/src/AccountFactoryWrapperDelegate.cpp b/src/libtomahawk/accounts/AccountFactoryWrapperDelegate.cpp similarity index 100% rename from src/AccountFactoryWrapperDelegate.cpp rename to src/libtomahawk/accounts/AccountFactoryWrapperDelegate.cpp diff --git a/src/AccountFactoryWrapperDelegate.h b/src/libtomahawk/accounts/AccountFactoryWrapperDelegate.h similarity index 100% rename from src/AccountFactoryWrapperDelegate.h rename to src/libtomahawk/accounts/AccountFactoryWrapperDelegate.h diff --git a/src/DelegateConfigWrapper.cpp b/src/libtomahawk/accounts/DelegateConfigWrapper.cpp similarity index 100% rename from src/DelegateConfigWrapper.cpp rename to src/libtomahawk/accounts/DelegateConfigWrapper.cpp diff --git a/src/DelegateConfigWrapper.h b/src/libtomahawk/accounts/DelegateConfigWrapper.h similarity index 100% rename from src/DelegateConfigWrapper.h rename to src/libtomahawk/accounts/DelegateConfigWrapper.h diff --git a/src/utils/GuiHelpers.cpp b/src/libtomahawk/utils/GuiHelpers.cpp similarity index 98% rename from src/utils/GuiHelpers.cpp rename to src/libtomahawk/utils/GuiHelpers.cpp index 6a77d1b6c..a682f8b9c 100644 --- a/src/utils/GuiHelpers.cpp +++ b/src/libtomahawk/utils/GuiHelpers.cpp @@ -22,7 +22,7 @@ #include "accounts/Account.h" #include "accounts/AccountManager.h" -#include "DelegateConfigWrapper.h" +#include "accounts/DelegateConfigWrapper.h" #include "TomahawkSettings.h" namespace TomahawkUtils @@ -169,4 +169,4 @@ openAccountConfig( Tomahawk::Accounts::Account* account, QWidget* parent, bool s } // namespace TomahawkUtils -#include "GuiHelpers.moc" \ No newline at end of file +#include "GuiHelpers.moc" diff --git a/src/utils/GuiHelpers.h b/src/libtomahawk/utils/GuiHelpers.h similarity index 80% rename from src/utils/GuiHelpers.h rename to src/libtomahawk/utils/GuiHelpers.h index f17ccd43c..9fe8f3873 100644 --- a/src/utils/GuiHelpers.h +++ b/src/libtomahawk/utils/GuiHelpers.h @@ -19,6 +19,8 @@ #ifndef TOMAHAWK_GUI_HELPERS_H #define TOMAHAWK_GUI_HELPERS_H +#include "DllMacro.h" + class QWidget; namespace Tomahawk { namespace Accounts { @@ -29,8 +31,8 @@ namespace Tomahawk { namespace TomahawkUtils { - void createAccountFromFactory( Tomahawk::Accounts::AccountFactory*, QWidget* parent ); - void openAccountConfig( Tomahawk::Accounts::Account*, QWidget* parent, bool showDelete = false ); + DLLEXPORT void createAccountFromFactory( Tomahawk::Accounts::AccountFactory*, QWidget* parent ); + DLLEXPORT void openAccountConfig( Tomahawk::Accounts::Account*, QWidget* parent, bool showDelete = false ); } -#endif \ No newline at end of file +#endif From 28207742208454371bdbda620656b5094f5a4abc Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 30 May 2012 21:58:16 +0200 Subject: [PATCH 156/433] * No need to pass DatabaseImpl into FuzzyIndex. --- src/libtomahawk/database/DatabaseImpl.cpp | 2 +- src/libtomahawk/database/FuzzyIndex.cpp | 3 +-- src/libtomahawk/database/FuzzyIndex.h | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index f45f813af..3c13d975e 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -79,7 +79,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) // in case of unclean shutdown last time: query.exec( "UPDATE source SET isonline = 'false'" ); - m_fuzzyIndex = new FuzzyIndex( *this, schemaUpdated ); + m_fuzzyIndex = new FuzzyIndex( schemaUpdated ); if ( schemaUpdated ) QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 0a26de604..fa13bfe30 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -38,9 +38,8 @@ using namespace lucene::queryParser; using namespace lucene::search; -FuzzyIndex::FuzzyIndex( DatabaseImpl& db, bool wipeIndex ) +FuzzyIndex::FuzzyIndex( bool wipeIndex ) : QObject() - , m_db( db ) , m_luceneReader( 0 ) , m_luceneSearcher( 0 ) { diff --git a/src/libtomahawk/database/FuzzyIndex.h b/src/libtomahawk/database/FuzzyIndex.h index 47fe1bf5d..8a66b491b 100644 --- a/src/libtomahawk/database/FuzzyIndex.h +++ b/src/libtomahawk/database/FuzzyIndex.h @@ -55,7 +55,7 @@ class FuzzyIndex : public QObject Q_OBJECT public: - explicit FuzzyIndex( DatabaseImpl& db, bool wipeIndex = false ); + explicit FuzzyIndex( bool wipeIndex = false ); ~FuzzyIndex(); void beginIndexing(); @@ -72,7 +72,6 @@ public slots: QMap< int, float > searchAlbum( const Tomahawk::query_ptr& query ); private: - DatabaseImpl& m_db; QMutex m_mutex; QString m_lucenePath; From 2ac0be98d30378c8d22e81fc61dd7a7c29616ab2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 30 May 2012 21:59:10 +0200 Subject: [PATCH 157/433] * Does this potentially fix our Windows non-latin username issues? --- src/libtomahawk/database/FuzzyIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index fa13bfe30..47e3cdb7e 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -44,7 +44,7 @@ FuzzyIndex::FuzzyIndex( bool wipeIndex ) , m_luceneSearcher( 0 ) { QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ); - m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toStdString().c_str() ); + m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toUtf8() ); m_analyzer = _CLNEW SimpleAnalyzer(); if ( wipeIndex ) From d655d66e9630b4568141e326194158e2d2cdd601 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Wed, 30 May 2012 22:18:29 +0000 Subject: [PATCH 158/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 32 ++++++++++++++++---------------- lang/tomahawk_bg.ts | 32 ++++++++++++++++---------------- lang/tomahawk_ca.ts | 32 ++++++++++++++++---------------- lang/tomahawk_de.ts | 32 ++++++++++++++++---------------- lang/tomahawk_en.ts | 32 ++++++++++++++++---------------- lang/tomahawk_es.ts | 32 ++++++++++++++++---------------- lang/tomahawk_fr.ts | 32 ++++++++++++++++---------------- lang/tomahawk_ja.ts | 32 ++++++++++++++++---------------- lang/tomahawk_pl.ts | 32 ++++++++++++++++---------------- lang/tomahawk_pt_BR.ts | 32 ++++++++++++++++---------------- lang/tomahawk_ru.ts | 32 ++++++++++++++++---------------- lang/tomahawk_sv.ts | 32 ++++++++++++++++---------------- lang/tomahawk_tr.ts | 32 ++++++++++++++++---------------- lang/tomahawk_zh_CN.ts | 32 ++++++++++++++++---------------- lang/tomahawk_zh_TW.ts | 32 ++++++++++++++++---------------- 15 files changed, 240 insertions(+), 240 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 693d49b9d..81cabaf74 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog حوار - + Description goes here أضف الوصف هنا - + Add Account أضف حساب @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online متصل - + Connecting... جاري الاتصال... - + Offline غير متصل @@ -440,17 +440,17 @@ connect and stream from you? DelegateConfigWrapper - + About عن - + Delete Account حذف الحساب - + About this Account عن هذا الحساب @@ -1602,32 +1602,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account أضف حساب - + Remove Account حذف الحساب - + %1 downloads تحميل %1 - + Online متصل - + Connecting... يجرى الاتصال... - + Offline خارج الهواء @@ -1944,7 +1944,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network أربط نفسك بتوماهاوك على الشبكة المحلية بطريقة مباشرة أوتوماتيكيا diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 4bf0686fb..1c6a97d26 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog - + Description goes here - + Add Account Добави регистрация @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -443,17 +443,17 @@ Tomahaw създаде доклад относно това и изпращай DelegateConfigWrapper - + About Относно - + Delete Account Изтрий регистрация - + About this Account Относно тази регистрация @@ -1606,32 +1606,32 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountDelegate - + Add Account Добави регистрация - + Remove Account Премахни регистрация - + %1 downloads %1 сваляния - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -1952,7 +1952,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Автоматично свързва Tomahawk с останалите копия на програмата, работещи в локалната мрежа. diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 4141f67e4..15d030ae2 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Diàleg - + Description goes here Aquí va la descripció - + Add Account Afegiu un compte @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online En línia - + Connecting... Connectant-se... - + Offline Fora de línia @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About Quant a - + Delete Account Esborra el Compte - + About this Account Quant a aquest compte @@ -1601,32 +1601,32 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountDelegate - + Add Account Afegeix un compte - + Remove Account Esborra el compte - + %1 downloads %1 descàrregues - + Online En Línia - + Connecting... Connectant-se... - + Offline Fora de Línia @@ -1943,7 +1943,7 @@ Torneu a autenticar-vos. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Connecta't automàticament a altres Tomahawks de la xarxa local diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index c4bd03f3e..c6e335b6b 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here Beschreibung hier - + Add Account Konto hinzufügen @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About Über - + Delete Account Konto entfernen - + About this Account Über dieses Konto @@ -1598,32 +1598,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Konto hinzufügen - + Remove Account Konto entfernen - + %1 downloads %1 Downloads - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -1938,7 +1938,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Automatisch mit anderen Tomahawks im Netzwerk verbinden diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 3056872fd..b75f263f6 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here Description goes here - + Add Account Add Account @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -440,17 +440,17 @@ connect and stream from you? DelegateConfigWrapper - + About About - + Delete Account Delete Account - + About this Account About this Account @@ -1602,32 +1602,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Add Account - + Remove Account Remove Account - + %1 downloads %1 downloads - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -1944,7 +1944,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 8cceabdff..4b8c763e7 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Diálogo - + Description goes here Descripción - + Add Account Añadir Cuenta @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About Acerca de - + Delete Account Eliminar Cuenta - + About this Account Acerca de esta Cuenta @@ -1600,32 +1600,32 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountDelegate - + Add Account Añadir Cuenta - + Remove Account Eliminar Cuenta - + %1 downloads %1 descargas - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -1942,7 +1942,7 @@ Hay que volverse a autenticar. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Conectarse automáticament a los Tomahawks de la red local diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 2c45a7cf0..da60d42b3 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here ici la description - + Add Account Ajouter un compte @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -440,17 +440,17 @@ se connecter et streamer depuis chez vous ? DelegateConfigWrapper - + About A propos - + Delete Account Supprimer le compte - + About this Account A propos de ce compte @@ -1602,32 +1602,32 @@ et des stations basés sur vos goûts. Tomahawk::Accounts::AccountDelegate - + Add Account Ajouter un compte - + Remove Account Supprimer le compte - + %1 downloads %1 téléchargements - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -1944,7 +1944,7 @@ Essayez de vous authentifier de nouveau. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Se connecter automatiquement aux Tomahawks sur le réseau local diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index d6c288d56..d6454b523 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog ダイアログ - + Description goes here - + Add Account アカウントを追加 @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online オンライン - + Connecting... 接続中... - + Offline オフライン @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account アカウントを削除 - + About this Account @@ -1605,32 +1605,32 @@ other: %n週間 Tomahawk::Accounts::AccountDelegate - + Add Account アカウントを追加 - + Remove Account アカウントを削除 - + %1 downloads - + Online オンライン - + Connecting... - + Offline ・オフライン @@ -1944,7 +1944,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index e6c330bcc..c468c636e 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog - + Description goes here Tutaj pojawi się opis - + Add Account Dodaj Konto @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Usuń Konto - + About this Account @@ -1601,32 +1601,32 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountDelegate - + Add Account Dodaj Konto - + Remove Account Usuń Konto - + %1 downloads pobrań: %1 - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -1940,7 +1940,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 9bdb318ba..0b6128255 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog - + Description goes here - + Add Account Adicionar Conta @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online - + Connecting... Conectando... - + Offline @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Excluir Conta - + About this Account @@ -1600,32 +1600,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Adicionar Conta - + Remove Account Remover Conta - + %1 downloads - + Online - + Connecting... Conectando... - + Offline @@ -1939,7 +1939,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 9edb57e90..d67ae2dda 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Диалог - + Description goes here Описание тут - + Add Account Добавить аккаунт @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -440,17 +440,17 @@ connect and stream from you? DelegateConfigWrapper - + About О - + Delete Account Удалить аккаунт - + About this Account Об этом аккаунте @@ -1599,32 +1599,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account Добавить аккаунт - + Remove Account Удалить аккаунт - + %1 downloads %1 загружено - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -1941,7 +1941,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network Автоматическое подключение к Tomahawks в локальной сети diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 557733c91..19cd6281e 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog Dialog - + Description goes here Beskrivning här - + Add Account Lägg till konto @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Online - + Connecting... Ansluter... - + Offline Offline @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Ta bort konto - + About this Account @@ -1598,32 +1598,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1937,7 +1937,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 2d019547d..b8e578c3a 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog İletişim Kutusu - + Description goes here Buraya açıklama gelecek - + Add Account Hesap Ekle @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online Çevrimiçi - + Connecting... Bağlanıyor... - + Offline Çevrimdışı @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account Hesabı Sil - + About this Account @@ -1597,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1936,7 +1936,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 98ab5ee42..d9d82390b 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog 对话框 - + Description goes here 注释于此处 - + Add Account 添加帐号 @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online 在线 - + Connecting... 连接中... - + Offline 离线 @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About - + Delete Account 删除账户 - + About this Account @@ -1597,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account - + Remove Account - + %1 downloads - + Online - + Connecting... - + Offline @@ -1936,7 +1936,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 9640610ba..60c611f11 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -2,17 +2,17 @@ AccountFactoryWrapper - + Dialog 對話框 - + Description goes here 說明放在這裡 - + Add Account 新增帳戶 @@ -20,17 +20,17 @@ AccountFactoryWrapperDelegate - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -439,17 +439,17 @@ connect and stream from you? DelegateConfigWrapper - + About 關於 - + Delete Account 刪除帳戶 - + About this Account 關於此帳戶 @@ -1597,32 +1597,32 @@ connect and stream from you? Tomahawk::Accounts::AccountDelegate - + Add Account 新增帳戶 - + Remove Account 刪除帳戶 - + %1 downloads - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -1936,7 +1936,7 @@ You may wish to try re-authenticating. Tomahawk::Accounts::ZeroconfFactory - + Automatically connect to Tomahawks on the local network 自動連接到區域網路上的 Tomahawks From 9be74e001c3833db5dd679b335da0b153144f4e4 Mon Sep 17 00:00:00 2001 From: Michael Coffey Date: Thu, 31 May 2012 12:17:08 +0100 Subject: [PATCH 159/433] Change the bundle script to find VLC 2.0 plugins, which are no longer in subfolders. A few have been commented out as they don't exist anymore (at least not with the same name). --- admin/mac/macdeploy.py | 309 ++++++++++++++++++++--------------------- 1 file changed, 154 insertions(+), 155 deletions(-) diff --git a/admin/mac/macdeploy.py b/admin/mac/macdeploy.py index 6d7987982..f6ab64641 100755 --- a/admin/mac/macdeploy.py +++ b/admin/mac/macdeploy.py @@ -29,159 +29,159 @@ LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.18.1.1/lib', VLC_PLUGINS=[ - 'access/libaccess_attachment_plugin.dylib', - #'access/libaccess_avio_plugin.dylib', - 'access/libaccess_fake_plugin.dylib', - 'access/libaccess_ftp_plugin.dylib', - 'access/libaccess_http_plugin.dylib', - 'access/libaccess_imem_plugin.dylib', - 'access/libaccess_mmap_plugin.dylib', - 'access/libaccess_mms_plugin.dylib', - 'access/libaccess_realrtsp_plugin.dylib', - 'access/libaccess_tcp_plugin.dylib', - 'access/libaccess_udp_plugin.dylib', - 'access/libcdda_plugin.dylib', - 'access/libfilesystem_plugin.dylib', - 'access/libqtcapture_plugin.dylib', - 'access/librtp_plugin.dylib', - 'access/libzip_plugin.dylib', - 'access_output/libaccess_output_dummy_plugin.dylib', - 'access_output/libaccess_output_file_plugin.dylib', - 'access_output/libaccess_output_http_plugin.dylib', - 'access_output/libaccess_output_shout_plugin.dylib', - 'access_output/libaccess_output_udp_plugin.dylib', - 'audio_filter/liba52tofloat32_plugin.dylib', - 'audio_filter/liba52tospdif_plugin.dylib', - 'audio_filter/libaudio_format_plugin.dylib', - 'audio_filter/libaudiobargraph_a_plugin.dylib', - 'audio_filter/libchorus_flanger_plugin.dylib', - 'audio_filter/libconverter_fixed_plugin.dylib', - 'audio_filter/libdolby_surround_decoder_plugin.dylib', - 'audio_filter/libdtstofloat32_plugin.dylib', - 'audio_filter/libdtstospdif_plugin.dylib', - 'audio_filter/libequalizer_plugin.dylib', - 'audio_filter/libheadphone_channel_mixer_plugin.dylib', - 'audio_filter/libmono_plugin.dylib', - 'audio_filter/libmpgatofixed32_plugin.dylib', - 'audio_filter/libnormvol_plugin.dylib', - 'audio_filter/libparam_eq_plugin.dylib', - 'audio_filter/libscaletempo_plugin.dylib', - 'audio_filter/libsimple_channel_mixer_plugin.dylib', - 'audio_filter/libspatializer_plugin.dylib', - 'audio_filter/libtrivial_channel_mixer_plugin.dylib', - 'audio_filter/libugly_resampler_plugin.dylib', - 'audio_mixer/libfloat32_mixer_plugin.dylib', - 'audio_mixer/libspdif_mixer_plugin.dylib', - 'audio_mixer/libtrivial_mixer_plugin.dylib', - 'audio_output/libaout_file_plugin.dylib', - 'audio_output/libauhal_plugin.dylib', - 'codec/liba52_plugin.dylib', - 'codec/libadpcm_plugin.dylib', - 'codec/libaes3_plugin.dylib', - 'codec/libaraw_plugin.dylib', - 'codec/libavcodec_plugin.dylib', - 'codec/libcc_plugin.dylib', - 'codec/libcdg_plugin.dylib', - 'codec/libdts_plugin.dylib', - 'codec/libfaad_plugin.dylib', - 'codec/libfake_plugin.dylib', - 'codec/libflac_plugin.dylib', - 'codec/libfluidsynth_plugin.dylib', - 'codec/libinvmem_plugin.dylib', - 'codec/liblpcm_plugin.dylib', - 'codec/libmpeg_audio_plugin.dylib', - 'codec/libpng_plugin.dylib', - 'codec/librawvideo_plugin.dylib', - 'codec/libspeex_plugin.dylib', - 'codec/libspudec_plugin.dylib', - 'codec/libtheora_plugin.dylib', - 'codec/libtwolame_plugin.dylib', - 'codec/libvorbis_plugin.dylib', - 'control/libgestures_plugin.dylib', - 'control/libhotkeys_plugin.dylib', - 'control/libmotion_plugin.dylib', - 'control/libnetsync_plugin.dylib', - 'control/libsignals_plugin.dylib', - 'demux/libaiff_plugin.dylib', - 'demux/libasf_plugin.dylib', - 'demux/libau_plugin.dylib', - #'demux/libavformat_plugin.dylib', - 'demux/libavi_plugin.dylib', - 'demux/libdemux_cdg_plugin.dylib', - 'demux/libdemuxdump_plugin.dylib', - 'demux/libdirac_plugin.dylib', - 'demux/libes_plugin.dylib', - 'demux/libflacsys_plugin.dylib', - 'demux/liblive555_plugin.dylib', - 'demux/libmkv_plugin.dylib', - 'demux/libmod_plugin.dylib', - 'demux/libmp4_plugin.dylib', - 'demux/libmpc_plugin.dylib', - 'demux/libmpgv_plugin.dylib', - 'demux/libnsc_plugin.dylib', - 'demux/libnsv_plugin.dylib', - 'demux/libnuv_plugin.dylib', - 'demux/libogg_plugin.dylib', - 'demux/libplaylist_plugin.dylib', - 'demux/libps_plugin.dylib', - 'demux/libpva_plugin.dylib', - 'demux/librawaud_plugin.dylib', - 'demux/librawdv_plugin.dylib', - 'demux/librawvid_plugin.dylib', - 'demux/libreal_plugin.dylib', - 'demux/libsmf_plugin.dylib', - 'demux/libts_plugin.dylib', - 'demux/libtta_plugin.dylib', - 'demux/libty_plugin.dylib', - 'demux/libvc1_plugin.dylib', - 'demux/libvoc_plugin.dylib', - 'demux/libwav_plugin.dylib', - 'demux/libxa_plugin.dylib', - 'meta_engine/libfolder_plugin.dylib', - 'meta_engine/libtaglib_plugin.dylib', - 'misc/libaudioscrobbler_plugin.dylib', - 'misc/libdummy_plugin.dylib', - 'misc/libexport_plugin.dylib', - 'misc/libfreetype_plugin.dylib', - 'misc/libgnutls_plugin.dylib', - 'misc/liblogger_plugin.dylib', - 'misc/liblua_plugin.dylib', - 'misc/libosd_parser_plugin.dylib', - 'misc/libquartztext_plugin.dylib', - 'misc/libstats_plugin.dylib', - 'misc/libvod_rtsp_plugin.dylib', - 'misc/libxml_plugin.dylib', - 'misc/libxtag_plugin.dylib', - 'mmx/libi420_rgb_mmx_plugin.dylib', - 'mmx/libi420_yuy2_mmx_plugin.dylib', - 'mmx/libi422_yuy2_mmx_plugin.dylib', - 'mmx/libmemcpymmx_plugin.dylib', - 'mmxext/libmemcpymmxext_plugin.dylib', - 'mux/libmux_asf_plugin.dylib', - 'mux/libmux_avi_plugin.dylib', - 'mux/libmux_dummy_plugin.dylib', - 'mux/libmux_mp4_plugin.dylib', - 'mux/libmux_mpjpeg_plugin.dylib', - 'mux/libmux_ogg_plugin.dylib', - 'mux/libmux_ps_plugin.dylib', - 'mux/libmux_ts_plugin.dylib', - 'mux/libmux_wav_plugin.dylib', - 'packetizer/libpacketizer_copy_plugin.dylib', - 'packetizer/libpacketizer_dirac_plugin.dylib', - 'packetizer/libpacketizer_flac_plugin.dylib', - 'packetizer/libpacketizer_h264_plugin.dylib', - 'packetizer/libpacketizer_mlp_plugin.dylib', - 'packetizer/libpacketizer_mpeg4audio_plugin.dylib', - 'packetizer/libpacketizer_mpeg4video_plugin.dylib', - 'packetizer/libpacketizer_mpegvideo_plugin.dylib', - 'packetizer/libpacketizer_vc1_plugin.dylib', - 'sse2/libi420_rgb_sse2_plugin.dylib', - 'sse2/libi420_yuy2_sse2_plugin.dylib', - 'sse2/libi422_yuy2_sse2_plugin.dylib', - 'stream_filter/libdecomp_plugin.dylib', - 'stream_filter/libstream_filter_rar_plugin.dylib', - 'stream_filter/libstream_filter_record_plugin.dylib', - 'visualization/libvisual_plugin.dylib', + 'libaccess_attachment_plugin.dylib', + #'libaccess_avio_plugin.dylib', + #'libaccess_fake_plugin.dylib', + 'libaccess_ftp_plugin.dylib', + 'libaccess_http_plugin.dylib', + 'libaccess_imem_plugin.dylib', + #'libaccess_mmap_plugin.dylib', + 'libaccess_mms_plugin.dylib', + 'libaccess_realrtsp_plugin.dylib', + 'libaccess_tcp_plugin.dylib', + 'libaccess_udp_plugin.dylib', + 'libcdda_plugin.dylib', + 'libfilesystem_plugin.dylib', + 'libqtcapture_plugin.dylib', + 'librtp_plugin.dylib', + 'libzip_plugin.dylib', + 'libaccess_output_dummy_plugin.dylib', + 'libaccess_output_file_plugin.dylib', + 'libaccess_output_http_plugin.dylib', + 'libaccess_output_shout_plugin.dylib', + 'libaccess_output_udp_plugin.dylib', + 'liba52tofloat32_plugin.dylib', + 'liba52tospdif_plugin.dylib', + 'libaudio_format_plugin.dylib', + 'libaudiobargraph_a_plugin.dylib', + 'libchorus_flanger_plugin.dylib', + 'libconverter_fixed_plugin.dylib', + 'libdolby_surround_decoder_plugin.dylib', + 'libdtstofloat32_plugin.dylib', + 'libdtstospdif_plugin.dylib', + 'libequalizer_plugin.dylib', + 'libheadphone_channel_mixer_plugin.dylib', + 'libmono_plugin.dylib', + 'libmpgatofixed32_plugin.dylib', + 'libnormvol_plugin.dylib', + 'libparam_eq_plugin.dylib', + 'libscaletempo_plugin.dylib', + 'libsimple_channel_mixer_plugin.dylib', + 'libspatializer_plugin.dylib', + 'libtrivial_channel_mixer_plugin.dylib', + 'libugly_resampler_plugin.dylib', + 'libfloat32_mixer_plugin.dylib', + #'libspdif_mixer_plugin.dylib', + #'libtrivial_mixer_plugin.dylib', + 'libaout_file_plugin.dylib', + 'libauhal_plugin.dylib', + 'liba52_plugin.dylib', + 'libadpcm_plugin.dylib', + 'libaes3_plugin.dylib', + 'libaraw_plugin.dylib', + 'libavcodec_plugin.dylib', + 'libcc_plugin.dylib', + 'libcdg_plugin.dylib', + 'libdts_plugin.dylib', + 'libfaad_plugin.dylib', + #'libfake_plugin.dylib', + 'libflac_plugin.dylib', + 'libfluidsynth_plugin.dylib', + #'libinvmem_plugin.dylib', + 'liblpcm_plugin.dylib', + 'libmpeg_audio_plugin.dylib', + 'libpng_plugin.dylib', + 'librawvideo_plugin.dylib', + 'libspeex_plugin.dylib', + 'libspudec_plugin.dylib', + 'libtheora_plugin.dylib', + 'libtwolame_plugin.dylib', + 'libvorbis_plugin.dylib', + 'libgestures_plugin.dylib', + 'libhotkeys_plugin.dylib', + 'libmotion_plugin.dylib', + 'libnetsync_plugin.dylib', + #'libsignals_plugin.dylib', + 'libaiff_plugin.dylib', + 'libasf_plugin.dylib', + 'libau_plugin.dylib', + #'libavformat_plugin.dylib', + 'libavi_plugin.dylib', + 'libdemux_cdg_plugin.dylib', + 'libdemuxdump_plugin.dylib', + 'libdirac_plugin.dylib', + 'libes_plugin.dylib', + 'libflacsys_plugin.dylib', + 'liblive555_plugin.dylib', + 'libmkv_plugin.dylib', + 'libmod_plugin.dylib', + 'libmp4_plugin.dylib', + 'libmpc_plugin.dylib', + 'libmpgv_plugin.dylib', + 'libnsc_plugin.dylib', + 'libnsv_plugin.dylib', + 'libnuv_plugin.dylib', + 'libogg_plugin.dylib', + 'libplaylist_plugin.dylib', + 'libps_plugin.dylib', + 'libpva_plugin.dylib', + 'librawaud_plugin.dylib', + 'librawdv_plugin.dylib', + 'librawvid_plugin.dylib', + 'libreal_plugin.dylib', + 'libsmf_plugin.dylib', + 'libts_plugin.dylib', + 'libtta_plugin.dylib', + 'libty_plugin.dylib', + 'libvc1_plugin.dylib', + 'libvoc_plugin.dylib', + 'libwav_plugin.dylib', + 'libxa_plugin.dylib', + 'libfolder_plugin.dylib', + 'libtaglib_plugin.dylib', + 'libaudioscrobbler_plugin.dylib', + 'libdummy_plugin.dylib', + 'libexport_plugin.dylib', + 'libfreetype_plugin.dylib', + 'libgnutls_plugin.dylib', + 'liblogger_plugin.dylib', + 'liblua_plugin.dylib', + 'libosd_parser_plugin.dylib', + 'libquartztext_plugin.dylib', + 'libstats_plugin.dylib', + 'libvod_rtsp_plugin.dylib', + 'libxml_plugin.dylib', + #'libxtag_plugin.dylib', + 'libi420_rgb_mmx_plugin.dylib', + 'libi420_yuy2_mmx_plugin.dylib', + 'libi422_yuy2_mmx_plugin.dylib', + 'libmemcpymmx_plugin.dylib', + 'libmemcpymmxext_plugin.dylib', + 'libmux_asf_plugin.dylib', + 'libmux_avi_plugin.dylib', + 'libmux_dummy_plugin.dylib', + 'libmux_mp4_plugin.dylib', + 'libmux_mpjpeg_plugin.dylib', + 'libmux_ogg_plugin.dylib', + 'libmux_ps_plugin.dylib', + 'libmux_ts_plugin.dylib', + 'libmux_wav_plugin.dylib', + 'libpacketizer_copy_plugin.dylib', + 'libpacketizer_dirac_plugin.dylib', + 'libpacketizer_flac_plugin.dylib', + 'libpacketizer_h264_plugin.dylib', + 'libpacketizer_mlp_plugin.dylib', + 'libpacketizer_mpeg4audio_plugin.dylib', + 'libpacketizer_mpeg4video_plugin.dylib', + 'libpacketizer_mpegvideo_plugin.dylib', + 'libpacketizer_vc1_plugin.dylib', + 'libi420_rgb_sse2_plugin.dylib', + 'libi420_yuy2_sse2_plugin.dylib', + 'libi422_yuy2_sse2_plugin.dylib', + 'libdecomp_plugin.dylib', + 'libstream_filter_rar_plugin.dylib', + 'libstream_filter_record_plugin.dylib', + 'libvisual_plugin.dylib', ] VLC_SEARCH_PATH=[ @@ -363,8 +363,7 @@ def FixVLCPlugin(abs_path, subdir): FixAllLibraries(broken_libs) #print "Copying plugin....%s %s %s" % (plugins_dir, subdir, os.path.join(abs_path.split('/')[-2:])) - plugindir = abs_path.split('/')[-2] - new_path = os.path.join(plugins_dir, subdir, plugindir, os.path.basename(abs_path)) + new_path = os.path.join(plugins_dir, subdir, os.path.basename(abs_path)) args = ['mkdir', '-p', os.path.dirname(new_path)] commands.append(args) args = ['ditto', '--arch=i386', '--arch=x86_64', abs_path, new_path] From f9e7ddfb86e971b354fd3bd2d2b8d69a78b5b3ce Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 13:54:35 +0200 Subject: [PATCH 160/433] * Trying toLocal8Bit() for fixing Windows with non-latin usernames. --- src/libtomahawk/database/FuzzyIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 47e3cdb7e..74b6aaa3d 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -44,7 +44,7 @@ FuzzyIndex::FuzzyIndex( bool wipeIndex ) , m_luceneSearcher( 0 ) { QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ); - m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toUtf8() ); + m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toLocal8Bit() ); m_analyzer = _CLNEW SimpleAnalyzer(); if ( wipeIndex ) From ac9064dcbc6c5c6985bb5894e699ea580e2cb2c2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 16:35:45 +0200 Subject: [PATCH 161/433] * Trying toLocal8Bit().data() for fixing Windows with non-latin usernames. --- src/libtomahawk/database/FuzzyIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 74b6aaa3d..8d5a74903 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -44,7 +44,7 @@ FuzzyIndex::FuzzyIndex( bool wipeIndex ) , m_luceneSearcher( 0 ) { QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ); - m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toLocal8Bit() ); + m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toLocal8Bit().data() ); m_analyzer = _CLNEW SimpleAnalyzer(); if ( wipeIndex ) From 602cf294d0003445423d04abae5ece675cf92ec5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 16:37:40 +0200 Subject: [PATCH 162/433] * Store path as a temporary QByteArray so the data doesn't get free'd again immediately. --- src/libtomahawk/database/FuzzyIndex.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 8d5a74903..082616658 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -44,7 +44,9 @@ FuzzyIndex::FuzzyIndex( bool wipeIndex ) , m_luceneSearcher( 0 ) { QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ); - m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toLocal8Bit().data() ); + QByteArray path = m_lucenePath.toLocal8Bit(); + + m_luceneDir = FSDirectory::getDirectory( path.data() ); m_analyzer = _CLNEW SimpleAnalyzer(); if ( wipeIndex ) From 5c1763e847ce944b88432aa166f8759f45bb4276 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 16:45:14 +0200 Subject: [PATCH 163/433] * Let's try that with Utf8 again. --- src/libtomahawk/database/FuzzyIndex.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 082616658..5a6255d14 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -44,9 +44,10 @@ FuzzyIndex::FuzzyIndex( bool wipeIndex ) , m_luceneSearcher( 0 ) { QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ); - QByteArray path = m_lucenePath.toLocal8Bit(); + QByteArray path = m_lucenePath.toUtf8(); + const char* cPath = path.constData(); - m_luceneDir = FSDirectory::getDirectory( path.data() ); + m_luceneDir = FSDirectory::getDirectory( cPath ); m_analyzer = _CLNEW SimpleAnalyzer(); if ( wipeIndex ) From 623850a281e5fda8ace9f942aa4fef8e1ecc9b3c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 16:54:44 +0200 Subject: [PATCH 164/433] * Catch any exceptions when opening the lucene FSDirectory. --- src/libtomahawk/database/FuzzyIndex.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 5a6255d14..86334d5a0 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -47,8 +47,17 @@ FuzzyIndex::FuzzyIndex( bool wipeIndex ) QByteArray path = m_lucenePath.toUtf8(); const char* cPath = path.constData(); - m_luceneDir = FSDirectory::getDirectory( cPath ); - m_analyzer = _CLNEW SimpleAnalyzer(); + tDebug() << "Opening Lucene directory:" << path; + try + { + m_luceneDir = FSDirectory::getDirectory( cPath ); + m_analyzer = _CLNEW SimpleAnalyzer(); + } + catch ( CLuceneError& error ) + { + tDebug() << "Caught CLucene error:" << error.what(); + Q_ASSERT( false ); + } if ( wipeIndex ) { @@ -92,7 +101,7 @@ FuzzyIndex::beginIndexing() } catch( CLuceneError& error ) { - qDebug() << "Caught CLucene error:" << error.what(); + tDebug() << "Caught CLucene error:" << error.what(); Q_ASSERT( false ); } } @@ -160,7 +169,7 @@ FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >& } catch( CLuceneError& error ) { - qDebug() << "Caught CLucene error:" << error.what(); + tDebug() << "Caught CLucene error:" << error.what(); Q_ASSERT( false ); } } From 751f0295647df33d4cc81ac2843b018edf4916d8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:22:18 +0200 Subject: [PATCH 165/433] * PlayableModel is now capable of dealing with trees. --- src/libtomahawk/playlist/PlayableModel.cpp | 309 +++++++++++++++++---- src/libtomahawk/playlist/PlayableModel.h | 21 +- 2 files changed, 273 insertions(+), 57 deletions(-) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index 5a6206399..e3a6c66db 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -42,9 +42,16 @@ PlayableModel::PlayableModel( QObject* parent ) , m_rootItem( new PlayableItem( 0, this ) ) , m_readOnly( true ) , m_style( Detailed ) + , m_loading( false ) { connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection ); + + m_header << tr( "Artist" ) << tr( "Title" ) << tr( "Composer" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" ) + << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" ) << tr( "Name" ); + + m_headerStyle[ Detailed ] << Artist << Track << Composer << Album << AlbumPos << Duration << Bitrate << Age << Year << Filesize << Origin << Score; + m_headerStyle[ Collection ] << Name << Composer << Duration << Bitrate << Age << Year << Filesize << Origin; } @@ -95,6 +102,10 @@ PlayableModel::columnCount( const QModelIndex& parent ) const return 1; break; + case Collection: + return 8; + break; + case Detailed: default: return 12; @@ -103,6 +114,20 @@ PlayableModel::columnCount( const QModelIndex& parent ) const } +bool +PlayableModel::hasChildren( const QModelIndex& parent ) const +{ + PlayableItem* parentItem = itemFromIndex( parent ); + if ( !parentItem ) + return false; + + if ( parentItem == m_rootItem ) + return true; + + return ( !parentItem->artist().isNull() || !parentItem->album().isNull() ); +} + + QModelIndex PlayableModel::parent( const QModelIndex& child ) const { @@ -124,42 +149,50 @@ PlayableModel::parent( const QModelIndex& child ) const QVariant -PlayableModel::data( const QModelIndex& index, int role ) const +PlayableModel::artistData( const artist_ptr& artist, int role ) const { - PlayableItem* entry = itemFromIndex( index ); - if ( !entry ) - return QVariant(); - - if ( role == Qt::DecorationRole ) - { - return QVariant(); - } - if ( role == Qt::SizeHintRole ) - { - return QSize( 0, 18 ); - } - - if ( role == Qt::TextAlignmentRole ) - { - return QVariant( columnAlignment( index.column() ) ); - } - - if ( role == StyleRole ) - { - return m_style; - } + return QSize( 0, 44 ); if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) return QVariant(); - const query_ptr& query = entry->query()->displayQuery(); - switch( index.column() ) + return artist->name(); +} + + +QVariant +PlayableModel::albumData( const album_ptr& album, int role ) const +{ + if ( role == Qt::SizeHintRole ) + return QSize( 0, 32 ); + + if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) + return QVariant(); + + return album->name(); +} + + +QVariant +PlayableModel::queryData( const query_ptr& query, int column, int role ) const +{ + if ( role == Qt::SizeHintRole ) + return QSize( 0, 18 ); + + if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) + return QVariant(); + + if ( !m_headerStyle.contains( m_style ) ) + return query->track(); + + switch( m_headerStyle[ m_style ].at( column ) ) { case Artist: return query->artist(); break; + case Name: case Track: return query->track(); break; @@ -191,7 +224,7 @@ PlayableModel::data( const QModelIndex& index, int role ) const } if ( query->numResults() ) { - switch( index.column() ) + switch( m_headerStyle[ m_style ].at( column ) ) { case Bitrate: if ( query->results().first()->bitrate() > 0 ) @@ -225,16 +258,58 @@ PlayableModel::data( const QModelIndex& index, int role ) const } +QVariant +PlayableModel::data( const QModelIndex& index, int role ) const +{ + PlayableItem* entry = itemFromIndex( index ); + if ( !entry ) + return QVariant(); + + if ( role == Qt::DecorationRole ) + { + return QVariant(); + } + + if ( role == Qt::TextAlignmentRole ) + { + return QVariant( columnAlignment( index.column() ) ); + } + + if ( role == StyleRole ) + { + return m_style; + } + + if ( !entry->query().isNull() ) + { + return queryData( entry->query()->displayQuery(), index.column(), role ); + } + else if ( !entry->artist().isNull() ) + { + return artistData( entry->artist(), role ); + } + else if ( !entry->album().isNull() ) + { + return albumData( entry->album(), role ); + } + + return QVariant(); +} + + QVariant PlayableModel::headerData( int section, Qt::Orientation orientation, int role ) const { Q_UNUSED( orientation ); - QStringList headers; - headers << tr( "Artist" ) << tr( "Title" ) << tr( "Composer" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" ); if ( role == Qt::DisplayRole && section >= 0 ) { - return headers.at( section ); + if ( m_headerStyle.contains( m_style ) ) + { + return m_header.at( m_headerStyle[ m_style ].at( section ) ); + } + else + return tr( "Name" ); } if ( role == Qt::TextAlignmentRole ) @@ -315,7 +390,7 @@ QStringList PlayableModel::mimeTypes() const { QStringList types; - types << "application/tomahawk.query.list"; + types << "application/tomahawk.mixed"; return types; } @@ -325,26 +400,134 @@ PlayableModel::mimeData( const QModelIndexList &indexes ) const { qDebug() << Q_FUNC_INFO; - QByteArray queryData; - QDataStream queryStream( &queryData, QIODevice::WriteOnly ); + QByteArray resultData; + QDataStream resultStream( &resultData, QIODevice::WriteOnly ); - foreach ( const QModelIndex& i, indexes ) + // lets try with artist only + bool fail = false; + foreach ( const QModelIndex& i, indexes) { - if ( i.column() > 0 ) + if ( i.column() > 0 || indexes.contains( i.parent() ) ) continue; - QModelIndex idx = index( i.row(), 0, i.parent() ); - PlayableItem* item = itemFromIndex( idx ); - if ( item ) + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->artist().isNull() ) + { + const artist_ptr& artist = item->artist(); + resultStream << artist->name(); + } + else + { + fail = true; + break; + } + } + if ( !fail ) + { + QMimeData* mimeData = new QMimeData(); + mimeData->setData( "application/tomahawk.metadata.artist", resultData ); + return mimeData; + } + + // lets try with album only + fail = false; + resultData.clear(); + foreach ( const QModelIndex& i, indexes ) + { + if ( i.column() > 0 || indexes.contains( i.parent() ) ) + continue; + + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->album().isNull() ) + { + const album_ptr& album = item->album(); + resultStream << album->artist()->name(); + resultStream << album->name(); + } + else + { + fail = true; + break; + } + } + if ( !fail ) + { + QMimeData* mimeData = new QMimeData(); + mimeData->setData( "application/tomahawk.metadata.album", resultData ); + return mimeData; + } + + // lets try with tracks only + fail = false; + resultData.clear(); + foreach ( const QModelIndex& i, indexes ) + { + if ( i.column() > 0 || indexes.contains( i.parent() ) ) + continue; + + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->result().isNull() ) + { + const result_ptr& result = item->result(); + resultStream << qlonglong( &result ); + } + else + { + fail = true; + break; + } + } + if ( !fail ) + { + QMimeData* mimeData = new QMimeData(); + mimeData->setData( "application/tomahawk.result.list", resultData ); + return mimeData; + } + + // Ok... we have to use mixed + resultData.clear(); + foreach ( const QModelIndex& i, indexes ) + { + if ( i.column() > 0 || indexes.contains( i.parent() ) ) + continue; + + PlayableItem* item = itemFromIndex( i ); + if ( !item ) + continue; + + if ( !item->artist().isNull() ) + { + const artist_ptr& artist = item->artist(); + resultStream << QString( "application/tomahawk.metadata.artist" ) << artist->name(); + } + else if ( !item->album().isNull() ) + { + const album_ptr& album = item->album(); + resultStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name(); + } + else if ( !item->result().isNull() ) + { + const result_ptr& result = item->result(); + resultStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result ); + } + else if ( !item->result().isNull() ) { const query_ptr& query = item->query(); - queryStream << qlonglong( &query ); + resultStream << QString( "application/tomahawk.query.list" ) << qlonglong( &query ); } } QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.query.list", queryData ); - + mimeData->setData( "application/tomahawk.mixed", resultData ); return mimeData; } @@ -354,7 +537,7 @@ PlayableModel::clear() { if ( rowCount( QModelIndex() ) ) { - emit loadingFinished(); + finishLoading(); emit beginResetModel(); delete m_rootItem; @@ -508,20 +691,6 @@ PlayableModel::remove( const QList& indexes ) } -PlayableItem* -PlayableModel::itemFromIndex( const QModelIndex& index ) const -{ - if ( index.isValid() ) - { - return static_cast( index.internalPointer() ); - } - else - { - return m_rootItem; - } -} - - void PlayableModel::onPlaybackStarted( const Tomahawk::result_ptr& result ) { @@ -591,3 +760,33 @@ PlayableModel::onDataChanged() if ( p && p->index.isValid() ) emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount() - 1 ) ); } + + +void +PlayableModel::startLoading() +{ + m_loading = true; + emit loadingStarted(); +} + + +void +PlayableModel::finishLoading() +{ + m_loading = false; + emit loadingFinished(); +} + + +PlayableItem* +PlayableModel::itemFromIndex( const QModelIndex& index ) const +{ + if ( index.isValid() ) + { + return static_cast( index.internalPointer() ); + } + else + { + return m_rootItem; + } +} diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 7ee0f763c..28db6a001 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -22,6 +22,7 @@ #define PLAYABLEMODEL_H #include +#include #include "PlaylistInterface.h" #include "Typedefs.h" @@ -38,7 +39,7 @@ Q_OBJECT public: enum PlayableItemStyle - { Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3 }; + { Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3, Collection = 4 }; enum PlayableModelRole { StyleRole = Qt::UserRole + 1 }; @@ -55,7 +56,8 @@ public: Year = 8, Filesize = 9, Origin = 10, - Score = 11 + Score = 11, + Name = 12 }; explicit PlayableModel( QObject* parent = 0 ); @@ -69,19 +71,27 @@ public: virtual bool isReadOnly() const { return m_readOnly; } virtual void setReadOnly( bool b ) { m_readOnly = b; } + virtual bool isLoading() const { return m_loading; } virtual QString title() const { return m_title; } virtual void setTitle( const QString& title ) { m_title = title; } virtual QString description() const { return m_description; } virtual void setDescription( const QString& description ) { m_description = description; } + virtual QPixmap icon() const { return m_icon; } + virtual void setIcon( const QPixmap& pixmap ) { m_icon = pixmap; } virtual int trackCount() const { return rowCount( QModelIndex() ); } virtual int rowCount( const QModelIndex& parent ) const; virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; + virtual bool hasChildren( const QModelIndex& parent ) const; virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; + + virtual QVariant artistData( const Tomahawk::artist_ptr& artist, int role = Qt::DisplayRole ) const; + virtual QVariant albumData( const Tomahawk::album_ptr& album, int role = Qt::DisplayRole ) const; + virtual QVariant queryData( const Tomahawk::query_ptr&, int column, int role = Qt::DisplayRole ) const; virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; virtual QStringList mimeTypes() const; @@ -134,6 +144,8 @@ public slots: protected: PlayableItem* rootItem() const { return m_rootItem; } + void startLoading(); + void finishLoading(); private slots: void onDataChanged(); @@ -152,8 +164,13 @@ private: QString m_title; QString m_description; + QPixmap m_icon; + + QHash< PlayableItemStyle, QList > m_headerStyle; + QStringList m_header; PlayableItemStyle m_style; + bool m_loading; }; #endif // PLAYABLEMODEL_H From bff7f01e22794f9e5abbacb68a34a77d11021e8f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:28:37 +0200 Subject: [PATCH 166/433] * Fixed warnings and added itemCountChanged( uint ) signal to PlayableModel. --- src/libtomahawk/playlist/PlayableModel.cpp | 8 ++++++++ src/libtomahawk/playlist/PlayableModel.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index e3a6c66db..00036d987 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -210,6 +210,7 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const break; case AlbumPos: + { QString tPos; if ( query->albumpos() != 0 ) { @@ -220,6 +221,10 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const return QString( "%1.%2" ).arg( QString::number( query->discnumber() ) ) .arg( tPos ); } + } + break; + + default: break; } if ( query->numResults() ) @@ -251,6 +256,9 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const case Score: return query->results().first()->score(); break; + + default: + break; } } diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 28db6a001..c529850e6 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -81,6 +81,7 @@ public: virtual void setIcon( const QPixmap& pixmap ) { m_icon = pixmap; } virtual int trackCount() const { return rowCount( QModelIndex() ); } + virtual int itemCount() const { return rowCount( QModelIndex() ); } virtual int rowCount( const QModelIndex& parent ) const; virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; @@ -117,6 +118,7 @@ signals: void shuffleModeChanged( bool enabled ); void trackCountChanged( unsigned int tracks ); + void itemCountChanged( unsigned int items ); void loadingStarted(); void loadingFinished(); From ca3b01362c032bf9deccea2e9e5f731218eeb83f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:29:12 +0200 Subject: [PATCH 167/433] * TreeModel inherits PlayableModel now. Will be renamed to CollectionModel soon. --- src/libtomahawk/playlist/TreeModel.cpp | 592 +------------------------ src/libtomahawk/playlist/TreeModel.h | 97 +--- 2 files changed, 19 insertions(+), 670 deletions(-) diff --git a/src/libtomahawk/playlist/TreeModel.cpp b/src/libtomahawk/playlist/TreeModel.cpp index 6194c8e90..2d0a7c575 100644 --- a/src/libtomahawk/playlist/TreeModel.cpp +++ b/src/libtomahawk/playlist/TreeModel.cpp @@ -38,12 +38,10 @@ using namespace Tomahawk; TreeModel::TreeModel( QObject* parent ) - : QAbstractItemModel( parent ) - , m_rootItem( new PlayableItem( 0, this ) ) - , m_infoId( uuid() ) - , m_columnStyle( AllColumns ) + : PlayableModel( parent ) , m_mode( DatabaseMode ) { + setStyle( Collection ); setIcon( QPixmap( RESPATH "images/music-icon.png" ) ); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); @@ -58,24 +56,6 @@ TreeModel::TreeModel( QObject* parent ) TreeModel::~TreeModel() { tDebug() << Q_FUNC_INFO; - - delete m_rootItem; -} - - -void -TreeModel::clear() -{ - if ( rowCount( QModelIndex() ) ) - { - emit loadingFinished(); - - emit beginResetModel(); - delete m_rootItem; - m_rootItem = 0; - m_rootItem = new PlayableItem( 0, this ); - emit endResetModel(); - } } @@ -107,45 +87,6 @@ TreeModel::getCover( const QModelIndex& index ) } -void -TreeModel::setCurrentItem( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - PlayableItem* oldEntry = itemFromIndex( m_currentIndex ); - if ( oldEntry ) - { - oldEntry->setIsPlaying( false ); - } - - PlayableItem* entry = itemFromIndex( index ); - if ( entry ) - { - m_currentIndex = index; - entry->setIsPlaying( true ); - } - else - { - m_currentIndex = QModelIndex(); - } -} - - -QModelIndex -TreeModel::index( int row, int column, const QModelIndex& parent ) const -{ - if ( !m_rootItem || row < 0 || column < 0 ) - return QModelIndex(); - - PlayableItem* parentItem = itemFromIndex( parent ); - PlayableItem* childItem = parentItem->children.value( row ); - if ( !childItem ) - return QModelIndex(); - - return createIndex( row, column, childItem ); -} - - bool TreeModel::canFetchMore( const QModelIndex& parent ) const { @@ -190,388 +131,11 @@ TreeModel::fetchMore( const QModelIndex& parent ) } -bool -TreeModel::hasChildren( const QModelIndex& parent ) const -{ - PlayableItem* parentItem = itemFromIndex( parent ); - if ( !parentItem ) - return false; - - if ( parentItem == m_rootItem ) - return true; - - return ( !parentItem->artist().isNull() || !parentItem->album().isNull() ); -} - - -int -TreeModel::rowCount( const QModelIndex& parent ) const -{ - if ( parent.column() > 0 ) - return 0; - - PlayableItem* parentItem = itemFromIndex( parent ); - if ( !parentItem ) - return 0; - - return parentItem->children.count(); -} - - -int -TreeModel::columnCount( const QModelIndex& parent ) const -{ - Q_UNUSED( parent ); - - if ( m_columnStyle == AllColumns ) - return 8; - else if ( m_columnStyle == TrackOnly ) - return 1; - - // UH.. - return 0; -} - - -QModelIndex -TreeModel::parent( const QModelIndex& child ) const -{ - PlayableItem* entry = itemFromIndex( child ); - if ( !entry ) - return QModelIndex(); - - PlayableItem* parentEntry = entry->parent(); - if ( !parentEntry ) - return QModelIndex(); - - PlayableItem* grandparentEntry = parentEntry->parent(); - if ( !grandparentEntry ) - return QModelIndex(); - - int row = grandparentEntry->children.indexOf( parentEntry ); - return createIndex( row, 0, parentEntry ); -} - - -QVariant -TreeModel::data( const QModelIndex& index, int role ) const -{ - PlayableItem* entry = itemFromIndex( index ); - if ( !entry ) - return QVariant(); - - if ( role == Qt::SizeHintRole ) - { - if ( !entry->result().isNull() || !entry->query().isNull() ) - { - return QSize( 128, 20 ); - } - else if ( !entry->album().isNull() ) - { - return QSize( 128, 32 ); - } - else if ( !entry->artist().isNull() ) - { - return QSize( 128, 44 ); - } - - return QSize( 128, 0 ); - } - - if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) - return QVariant(); - - if ( !entry->artist().isNull() && index.column() == Name ) - { - return entry->artist()->name(); - } - else if ( !entry->album().isNull() && index.column() == Name ) - { - return entry->album()->name(); - } - else if ( !entry->result().isNull() ) - { - const result_ptr& result = entry->result(); - unsigned int discnumber = 0; - if ( !entry->query().isNull() ) - discnumber = entry->query()->discnumber(); - if ( discnumber == 0 ) - discnumber = result->discnumber(); - - unsigned int albumpos = 0; - if ( !entry->query().isNull() ) - albumpos = entry->query()->albumpos(); - if ( albumpos == 0 ) - albumpos = result->albumpos(); - - switch( index.column() ) - { - case Name: - return QString( "%1%2%3" ).arg( discnumber > 0 ? QString( "%1." ).arg( discnumber ) : QString() ) - .arg( albumpos > 0 ? QString( "%1. ").arg( albumpos ) : QString() ) - .arg( result->track() ); - - case Duration: - return TomahawkUtils::timeToString( result->duration() ); - - case Bitrate: - if ( result->bitrate() > 0 ) - return result->bitrate(); - break; - - case Age: - return TomahawkUtils::ageToString( QDateTime::fromTime_t( result->modificationTime() ) ); - - case Year: - if ( result->year() != 0 ) - return result->year(); - break; - - case Filesize: - return TomahawkUtils::filesizeToString( result->size() ); - - case Origin: - return result->friendlySource(); - - case AlbumPosition: - return result->albumpos(); - - case Composer: - if ( !result->composer().isNull() ) - return result->composer()->name(); - break; - - default: - return QVariant(); - } - } - else if ( !entry->query().isNull() ) - { - const query_ptr& query = entry->query(); - switch( index.column() ) - { - case Name: - return QString( "%1%2%3" ).arg( query->discnumber() > 0 ? QString( "%1." ).arg( query->discnumber() ) : QString() ) - .arg( query->albumpos() > 0 ? QString( "%1. ").arg( query->albumpos() ) : QString() ) - .arg( query->track() ); - - case AlbumPosition: - return entry->query()->albumpos(); - - default: - return QVariant(); - } - } - - return QVariant(); -} - - -QVariant -TreeModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - QStringList headers; - headers << tr( "Name" ) << tr( "Composer" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ); - if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 ) - { - return headers.at( section ); - } - - return QVariant(); -} - - -Qt::ItemFlags -TreeModel::flags( const QModelIndex& index ) const -{ - Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index ); - - if ( index.isValid() && index.column() == 0 ) - { - PlayableItem* item = itemFromIndex( index ); - if ( item && !item->result().isNull() ) - return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; - if ( item && ( !item->album().isNull() || !item->artist().isNull() ) ) - return Qt::ItemIsDragEnabled | defaultFlags; - } - - return defaultFlags; -} - - -QStringList -TreeModel::mimeTypes() const -{ - QStringList types; - types << "application/tomahawk.mixed"; - return types; -} - - -QMimeData* -TreeModel::mimeData( const QModelIndexList &indexes ) const -{ - qDebug() << Q_FUNC_INFO; - - QByteArray resultData; - QDataStream resultStream( &resultData, QIODevice::WriteOnly ); - - // lets try with artist only - bool fail = false; - foreach ( const QModelIndex& i, indexes) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->artist().isNull() ) - { - const artist_ptr& artist = item->artist(); - resultStream << artist->name(); - } - else - { - fail = true; - break; - } - } - if ( !fail ) - { - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.metadata.artist", resultData ); - return mimeData; - } - - // lets try with album only - fail = false; - resultData.clear(); - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->album().isNull() ) - { - const album_ptr& album = item->album(); - resultStream << album->artist()->name(); - resultStream << album->name(); - } - else - { - fail = true; - break; - } - } - if ( !fail ) - { - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.metadata.album", resultData ); - return mimeData; - } - - // lets try with tracks only - fail = false; - resultData.clear(); - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->result().isNull() ) - { - const result_ptr& result = item->result(); - resultStream << qlonglong( &result ); - } - else - { - fail = true; - break; - } - } - if ( !fail ) - { - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.result.list", resultData ); - return mimeData; - } - - // Ok... we have to use mixed - resultData.clear(); - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 || indexes.contains( i.parent() ) ) - continue; - - PlayableItem* item = itemFromIndex( i ); - if ( !item ) - continue; - - if ( !item->artist().isNull() ) - { - const artist_ptr& artist = item->artist(); - resultStream << QString( "application/tomahawk.metadata.artist" ) << artist->name(); - } - else if ( !item->album().isNull() ) - { - const album_ptr& album = item->album(); - resultStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name(); - } - else if ( !item->result().isNull() ) - { - const result_ptr& result = item->result(); - resultStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result ); - } - } - - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.mixed", resultData ); - return mimeData; -} - - -void -TreeModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( index.column() > 0 ) - return; - - PlayableItem* item = itemFromIndex( index ); - if ( item ) - { - emit beginRemoveRows( index.parent(), index.row(), index.row() ); - delete item; - emit endRemoveRows(); - } -} - - -void -TreeModel::removeIndexes( const QList& indexes ) -{ - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } -} - - void TreeModel::addAllCollections() { - emit loadingStarted(); + startLoading(); + DatabaseCommand_AllArtists* cmd = new DatabaseCommand_AllArtists(); connect( cmd, SIGNAL( artists( QList ) ), @@ -587,7 +151,7 @@ TreeModel::addAllCollections() connect( source->collection().data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ), Qt::UniqueConnection ); } - m_title = tr( "All Artists" ); + setTitle( tr( "All Artists" ) ); } @@ -597,7 +161,7 @@ TreeModel::addArtists( const artist_ptr& artist ) if ( artist.isNull() ) return; - emit loadingStarted(); + startLoading(); QList artists; artists << artist; @@ -608,7 +172,7 @@ TreeModel::addArtists( const artist_ptr& artist ) void TreeModel::fetchAlbums( const artist_ptr& artist ) { - emit loadingStarted(); + startLoading(); connect( artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ), Qt::UniqueConnection ); @@ -624,7 +188,7 @@ TreeModel::onAlbumsFound( const QList& albums, ModelMode mo if ( m_mode != mode ) return; - Artist* artist = qobject_cast< Artist* >( sender() ); + Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() ); if ( !artist ) return; @@ -640,7 +204,7 @@ TreeModel::onAlbumsFound( const QList& albums, ModelMode mo void TreeModel::addAlbums( const QModelIndex& parent, const QList& albums ) { - emit loadingFinished(); + finishLoading(); if ( !albums.count() ) return; @@ -672,7 +236,7 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent, bool au { Q_UNUSED( autoRefetch ); - emit loadingStarted(); + startLoading(); connect( album.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), SLOT( onTracksFound( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) ); @@ -755,12 +319,7 @@ TreeModel::onCollectionChanged() void TreeModel::onArtistsAdded( const QList& artists ) { - emit loadingFinished(); - if ( !artists.count() ) - { - emit itemCountChanged( rowCount( QModelIndex() ) ); - return; - } + finishLoading(); int c = rowCount( QModelIndex() ); QPair< int, int > crows; @@ -772,20 +331,19 @@ TreeModel::onArtistsAdded( const QList& artists ) PlayableItem* artistitem; foreach( const artist_ptr& artist, artists ) { - artistitem = new PlayableItem( artist, m_rootItem ); - artistitem->index = createIndex( m_rootItem->children.count() - 1, 0, artistitem ); + artistitem = new PlayableItem( artist, rootItem() ); + artistitem->index = createIndex( rootItem()->children.count() - 1, 0, artistitem ); connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } emit endInsertRows(); - emit itemCountChanged( rowCount( QModelIndex() ) ); } void TreeModel::onTracksAdded( const QList& tracks, const QModelIndex& parent ) { - emit loadingFinished(); + finishLoading(); if ( !tracks.count() ) return; @@ -817,135 +375,17 @@ TreeModel::onTracksFound( const QList& tracks, Tomahawk::Mo if ( mode != m_mode || collection != m_collection ) return; - Album* album = qobject_cast( sender() ); + Tomahawk::Album* album = qobject_cast( sender() ); QModelIndex idx = indexFromAlbum( album->weakRef().toStrongRef() ); onTracksAdded( tracks, idx ); } -void -TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) -{ - if ( requestData.caller != m_infoId ) - { - return; - } - - switch ( requestData.type ) - { - case Tomahawk::InfoSystem::InfoAlbumSongs: - { - m_receivedInfoData.append( requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >() ); - - QVariantMap returnedData = output.value< QVariantMap >(); - if ( !returnedData.isEmpty() ) - { - emit loadingFinished(); - - QList< QVariant > rows = requestData.customData[ "rows" ].toList(); - QModelIndex idx = index( rows.first().toUInt(), 0, index( rows.at( 1 ).toUInt(), 0, QModelIndex() ) ); - if ( rowCount( idx ) ) - return; - - Tomahawk::InfoSystem::InfoStringHash inputInfo; - inputInfo = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - - QStringList tracks = returnedData[ "tracks" ].toStringList(); - QList ql; - - //TODO: Figure out how to do this with a multi-disk album without breaking the - // current behaviour. I just know too little about InfoSystem to deal with - // it right now, I've only taken the liberty of adding Query::setDiscNumber - // which should make this easier. --Teo 11/2011 - unsigned int trackNo = 1; - - foreach ( const QString& trackName, tracks ) - { - query_ptr query = Query::get( inputInfo[ "artist" ], trackName, inputInfo[ "album" ] ); - query->setAlbumPos( trackNo++ ); - ql << query; - } - Pipeline::instance()->resolve( ql ); - - onTracksAdded( ql, idx ); - } - else if ( m_receivedInfoData.count() == 2 /* FIXME */ ) - { - // If the second load got no data, but the first load did, don't do anything - QList< QVariant > rows = requestData.customData[ "rows" ].toList(); - QModelIndex idx = index( rows.first().toUInt(), 0, index( rows.at( 1 ).toUInt(), 0, QModelIndex() ) ); - if ( rowCount( idx ) ) - return; - - if ( requestData.customData[ "refetch" ].toBool() ) - { - setMode( DatabaseMode ); - - Tomahawk::InfoSystem::InfoStringHash inputInfo; - inputInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - artist_ptr artist = Artist::get( inputInfo[ "artist" ], false ); - album_ptr album = Album::get( artist, inputInfo[ "album" ], false ); - - addTracks( album, QModelIndex() ); - } - else - emit loadingFinished(); - } - - break; - } - - default: - { - Q_ASSERT( false ); - break; - } - } -} - - -void -TreeModel::onPlaybackStarted( const Tomahawk::result_ptr& result ) -{ - PlayableItem* oldEntry = itemFromIndex( m_currentIndex ); - if ( oldEntry && ( oldEntry->result().isNull() || oldEntry->result().data() != result.data() ) ) - { - oldEntry->setIsPlaying( false ); - } -} - - -void -TreeModel::onPlaybackStopped() -{ - PlayableItem* oldEntry = itemFromIndex( m_currentIndex ); - if ( oldEntry ) - { - oldEntry->setIsPlaying( false ); - } -} - - -void -TreeModel::onDataChanged() -{ - PlayableItem* p = (PlayableItem*)sender(); - emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) ); -} - - -void -TreeModel::setColumnStyle( TreeModel::ColumnStyle style ) -{ - m_columnStyle = style; -} - - QModelIndex TreeModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const { - for ( int i = 0; i < rowCount(); i++ ) + for ( int i = 0; i < rowCount( QModelIndex() ); i++ ) { QModelIndex idx = index( i, 0, QModelIndex() ); PlayableItem* item = itemFromIndex( idx ); diff --git a/src/libtomahawk/playlist/TreeModel.h b/src/libtomahawk/playlist/TreeModel.h index 21ec55591..6fb91d3c3 100644 --- a/src/libtomahawk/playlist/TreeModel.h +++ b/src/libtomahawk/playlist/TreeModel.h @@ -27,11 +27,10 @@ #include "Album.h" #include "Query.h" #include "Result.h" +#include "PlayableModel.h" #include "PlaylistInterface.h" #include "database/DatabaseCommand_AllArtists.h" -#include "infosystem/InfoSystem.h" - #include "DllMacro.h" #include "Typedefs.h" @@ -39,57 +38,17 @@ class QMetaData; class PlayableItem; -class DLLEXPORT TreeModel : public QAbstractItemModel +class DLLEXPORT TreeModel : public PlayableModel { Q_OBJECT public: - enum Columns { - Name = 0, - Composer, - Duration, - Bitrate, - Age, - Year, - Filesize, - Origin, - AlbumPosition - }; - - enum ColumnStyle - { AllColumns = 0, TrackOnly }; - explicit TreeModel( QObject* parent = 0 ); virtual ~TreeModel(); - virtual QModelIndex index( int row, int column, const QModelIndex& parent ) const; - virtual QModelIndex parent( const QModelIndex& child ) const; - - virtual bool isReadOnly() const { return true; } - - virtual int trackCount() const { return rowCount( QModelIndex() ); } - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual bool hasChildren( const QModelIndex& parent = QModelIndex() ) const; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const; - virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; - virtual Tomahawk::ModelMode mode() const { return m_mode; } virtual void setMode( Tomahawk::ModelMode mode ); - virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; - virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; - - virtual void clear(); - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; - virtual QStringList mimeTypes() const; - virtual Qt::ItemFlags flags( const QModelIndex& index ) const; - - virtual QPersistentModelIndex currentItem() { return m_currentIndex; } - Tomahawk::collection_ptr collection() const; void addAllCollections(); @@ -102,47 +61,14 @@ public: void getCover( const QModelIndex& index ); - ColumnStyle columnStyle() const { return m_columnStyle; } - void setColumnStyle( ColumnStyle style ); - - virtual QString title() const { return m_title; } - virtual QString description() const { return m_description; } - virtual QPixmap icon() const { return m_icon; } - virtual void setTitle( const QString& title ) { m_title = title; } - virtual void setDescription( const QString& description ) { m_description = description; } - virtual void setIcon( const QPixmap& pixmap ) { m_icon = pixmap; } - QModelIndex indexFromArtist( const Tomahawk::artist_ptr& artist ) const; QModelIndex indexFromAlbum( const Tomahawk::album_ptr& album ) const; - PlayableItem* itemFromIndex( const QModelIndex& index ) const - { - if ( index.isValid() ) - { - return static_cast( index.internalPointer() ); - } - else - { - return m_rootItem; - } - } public slots: - virtual void setCurrentItem( const QModelIndex& index ); - - virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode /*mode*/ ) {} - virtual void setShuffled( bool /*shuffled*/ ) {} - void addAlbums( const QModelIndex& parent, const QList& albums ); signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - void modeChanged( Tomahawk::ModelMode mode ); - void itemCountChanged( unsigned int items ); - - void loadingStarted(); - void loadingFinished(); protected: bool canFetchMore( const QModelIndex& parent ) const; @@ -154,31 +80,14 @@ private slots: void onTracksAdded( const QList& tracks, const QModelIndex& index ); void onTracksFound( const QList& tracks, Tomahawk::ModelMode mode, Tomahawk::collection_ptr collection ); - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); - - void onPlaybackStarted( const Tomahawk::result_ptr& result ); - void onPlaybackStopped(); - - void onDataChanged(); - void onSourceAdded( const Tomahawk::source_ptr& source ); void onCollectionChanged(); private: - QPersistentModelIndex m_currentIndex; - PlayableItem* m_rootItem; - QString m_infoId; - - QString m_title; - QString m_description; - QPixmap m_icon; - ColumnStyle m_columnStyle; Tomahawk::ModelMode m_mode; + Tomahawk::collection_ptr m_collection; QList m_artistsFilter; - - Tomahawk::collection_ptr m_collection; - QList m_receivedInfoData; }; #endif // ALBUMMODEL_H From 7a8818ae94104f4741582549088cb96b8589ca9d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:29:38 +0200 Subject: [PATCH 168/433] * Style fix in DbCmd_SetPlaylistRevision. --- src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp b/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp index f166d0fa0..00c8cf6bb 100644 --- a/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp +++ b/src/libtomahawk/database/DatabaseCommand_SetPlaylistRevision.cpp @@ -167,7 +167,6 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib ) foreach( const plentry_ptr& e, m_entries ) { - adde.bindValue( 0, e->query()->track() ); adde.bindValue( 1, e->query()->artist() ); adde.bindValue( 2, e->query()->album() ); From 7bdc5ea4f28fda51ebb7e27c8d054869be5bfbfc Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:31:01 +0200 Subject: [PATCH 169/433] * OverlayWidget now expects a QAbstractItemView which it automatically connects all signals to. --- src/libtomahawk/widgets/OverlayWidget.cpp | 33 ++++++++++++++++++++++- src/libtomahawk/widgets/OverlayWidget.h | 8 ++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index 83e43a2fc..5261fe986 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -30,7 +30,7 @@ #define OPACITY 0.70 -OverlayWidget::OverlayWidget( QWidget* parent ) +OverlayWidget::OverlayWidget( QAbstractItemView* parent ) : QWidget( parent ) // this is on purpose! , m_opacity( 0.00 ) , m_parent( parent ) @@ -42,6 +42,12 @@ OverlayWidget::OverlayWidget( QWidget* parent ) m_timer.setSingleShot( true ); connect( &m_timer, SIGNAL( timeout() ), this, SLOT( hide() ) ); + + if ( m_parent->model() ) + { + connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + } + connect( m_parent, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); #ifdef Q_WS_MAC QFont f( font() ); @@ -120,6 +126,31 @@ OverlayWidget::shown() const } +void +OverlayWidget::onViewChanged() +{ + if ( m_parent->model()->rowCount() ) + { + hide(); + } + else + { + show(); + } +} + + +void +OverlayWidget::onViewModelChanged() +{ + if ( m_parent->model() ) + { + connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + onViewChanged(); + } +} + + void OverlayWidget::paintEvent( QPaintEvent* event ) { diff --git a/src/libtomahawk/widgets/OverlayWidget.h b/src/libtomahawk/widgets/OverlayWidget.h index 91de2d2bf..352049799 100644 --- a/src/libtomahawk/widgets/OverlayWidget.h +++ b/src/libtomahawk/widgets/OverlayWidget.h @@ -31,7 +31,7 @@ Q_OBJECT Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) public: - OverlayWidget( QWidget* parent ); + OverlayWidget( QAbstractItemView* parent ); ~OverlayWidget(); qreal opacity() const { return m_opacity; } @@ -49,12 +49,16 @@ public slots: protected: // void changeEvent( QEvent* e ); void paintEvent( QPaintEvent* event ); + +private slots: + void onViewChanged(); + void onViewModelChanged(); private: QString m_text; qreal m_opacity; - QWidget* m_parent; + QAbstractItemView* m_parent; QTimer m_timer; }; From 72528ab08964885548d8026f0d11c1b7db48f6cc Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:31:43 +0200 Subject: [PATCH 170/433] * LoadingSpinner inherits AnimatedSpinner and automatically connects to a QAbstractItemView. --- src/libtomahawk/utils/AnimatedSpinner.cpp | 28 +++++++++++++++++++++-- src/libtomahawk/utils/AnimatedSpinner.h | 21 +++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/utils/AnimatedSpinner.cpp b/src/libtomahawk/utils/AnimatedSpinner.cpp index c3cffd547..2d66e7273 100644 --- a/src/libtomahawk/utils/AnimatedSpinner.cpp +++ b/src/libtomahawk/utils/AnimatedSpinner.cpp @@ -31,7 +31,7 @@ #include "utils/Logger.h" -AnimatedSpinner::AnimatedSpinner( QWidget *parent ) +AnimatedSpinner::AnimatedSpinner( QWidget* parent ) : QWidget( parent ) , m_showHide( new QTimeLine ) , m_animation( new QTimeLine ) @@ -41,7 +41,7 @@ AnimatedSpinner::AnimatedSpinner( QWidget *parent ) } -AnimatedSpinner::AnimatedSpinner( const QSize size, bool autoStart ) +AnimatedSpinner::AnimatedSpinner( const QSize& size, bool autoStart ) : QWidget() , m_showHide( new QTimeLine ) , m_animation( new QTimeLine ) @@ -260,3 +260,27 @@ AnimatedSpinner::segmentCount() const { return 11; } + + +LoadingSpinner::LoadingSpinner( QAbstractItemView* parent ) + : AnimatedSpinner( parent ) + , m_parent( parent ) +{ + if ( m_parent->model() ) + { + connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( fadeIn() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( fadeOut() ), Qt::UniqueConnection ); + } + connect( m_parent, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); +} + + +void +LoadingSpinner::onViewModelChanged() +{ + if ( m_parent->model() ) + { + connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( fadeIn() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( fadeOut() ), Qt::UniqueConnection ); + } +} diff --git a/src/libtomahawk/utils/AnimatedSpinner.h b/src/libtomahawk/utils/AnimatedSpinner.h index 0bf502246..19ec3090e 100644 --- a/src/libtomahawk/utils/AnimatedSpinner.h +++ b/src/libtomahawk/utils/AnimatedSpinner.h @@ -26,6 +26,7 @@ #include #include #include +#include class QTimeLine; class QHideEvent; @@ -42,9 +43,10 @@ class QTimerEvent; class DLLEXPORT AnimatedSpinner : public QWidget { Q_OBJECT + public: - explicit AnimatedSpinner( QWidget *parent = 0 ); // widget mode - AnimatedSpinner( const QSize size, bool autoStart ); // pixmap mode + explicit AnimatedSpinner( QWidget* parent = 0 ); // widget mode + AnimatedSpinner( const QSize& size, bool autoStart ); // pixmap mode QSize sizeHint() const; @@ -87,4 +89,19 @@ private: bool m_autoCenter; }; + +class LoadingSpinner : public AnimatedSpinner +{ + Q_OBJECT + +public: + explicit LoadingSpinner( QAbstractItemView* parent = 0 ); // widget mode + +private slots: + void onViewModelChanged(); + +private: + QAbstractItemView* m_parent; +}; + #endif From 3e8d131c164a45674ee8dbfc3f9b244a5be232a8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:33:05 +0200 Subject: [PATCH 171/433] * AlbumView now uses LoadingSpinner and new OverlayWidget. --- src/libtomahawk/playlist/AlbumView.cpp | 27 +++++--------------------- src/libtomahawk/playlist/AlbumView.h | 2 -- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 1bcd30565..321d1d54b 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -49,7 +49,7 @@ AlbumView::AlbumView( QWidget* parent ) , m_model( 0 ) , m_proxyModel( 0 ) , m_delegate( 0 ) - , m_loadingSpinner( new AnimatedSpinner( this ) ) + , m_loadingSpinner( new LoadingSpinner( this ) ) , m_overlay( new OverlayWidget( this ) ) , m_contextMenu( new ContextMenu( this ) ) , m_inited( false ) @@ -75,6 +75,10 @@ AlbumView::AlbumView( QWidget* parent ) setAutoFitItems( true ); setProxyModel( new AlbumProxyModel( this ) ); +/* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); + m_overlay->setText( tr( "This collection doesn't have any recent albums." ) );*/ + m_overlay->setText( tr( "Nothing found." ) ); + connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); @@ -124,10 +128,6 @@ AlbumView::setAlbumModel( AlbumModel* model ) connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) ); - connect( m_model, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemCountChanged( unsigned int ) ) ); - connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); - connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); - emit modelChanged(); } @@ -165,23 +165,6 @@ AlbumView::onItemActivated( const QModelIndex& index ) } -void -AlbumView::onItemCountChanged( unsigned int items ) -{ - if ( items == 0 ) - { - if ( m_model->collection().isNull() || ( !m_model->collection().isNull() && m_model->collection()->source()->isLocal() ) ) - m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); - else - m_overlay->setText( tr( "This collection doesn't have any recent albums." ) ); - - m_overlay->show(); - } - else - m_overlay->hide(); -} - - void AlbumView::scrollContentsBy( int dx, int dy ) { diff --git a/src/libtomahawk/playlist/AlbumView.h b/src/libtomahawk/playlist/AlbumView.h index f861846c9..0a231f002 100644 --- a/src/libtomahawk/playlist/AlbumView.h +++ b/src/libtomahawk/playlist/AlbumView.h @@ -50,7 +50,6 @@ public: AlbumModel* model() const { return m_model; } AlbumProxyModel* proxyModel() const { return m_proxyModel; } -// PlaylistItemDelegate* delegate() { return m_delegate; } bool autoFitItems() const { return m_autoFitItems; } void setAutoFitItems( bool b ) { m_autoFitItems = b; } @@ -86,7 +85,6 @@ protected slots: virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous ); private slots: - void onItemCountChanged( unsigned int items ); void onFilterChanged( const QString& filter ); void onCustomContextMenu( const QPoint& pos ); From 2860bfc704d8509a3b35ba8e61c7abd83e53d766 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:33:52 +0200 Subject: [PATCH 172/433] * ArtistView now uses LoadingSpinner and new OverlayWidget. --- src/libtomahawk/playlist/ArtistView.cpp | 9 ++++----- src/libtomahawk/playlist/ArtistView.h | 4 +++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/ArtistView.cpp index e080847f0..73387be7b 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/ArtistView.cpp @@ -51,8 +51,7 @@ ArtistView::ArtistView( QWidget* parent ) , m_overlay( new OverlayWidget( this ) ) , m_model( 0 ) , m_proxyModel( 0 ) -// , m_delegate( 0 ) - , m_loadingSpinner( new AnimatedSpinner( this ) ) + , m_loadingSpinner( new LoadingSpinner( this ) ) , m_updateContextView( true ) , m_contextMenu( new ContextMenu( this ) ) , m_showModes( true ) @@ -137,8 +136,6 @@ ArtistView::setTreeModel( TreeModel* model ) m_proxyModel->sort( 0 ); } - connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); - connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); connect( m_proxyModel, SIGNAL( filteringStarted() ), SLOT( onFilteringStarted() ) ); connect( m_proxyModel, SIGNAL( filteringFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); @@ -148,7 +145,7 @@ ArtistView::setTreeModel( TreeModel* model ) guid(); // this will set the guid on the header - if ( model->columnStyle() == TreeModel::TrackOnly ) + if ( model->style() == PlayableModel::Large ) { setHeaderHidden( true ); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); @@ -158,6 +155,8 @@ ArtistView::setTreeModel( TreeModel* model ) setHeaderHidden( false ); setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); } + + emit modelChanged(); } diff --git a/src/libtomahawk/playlist/ArtistView.h b/src/libtomahawk/playlist/ArtistView.h index 90c76e66f..f113c78c3 100644 --- a/src/libtomahawk/playlist/ArtistView.h +++ b/src/libtomahawk/playlist/ArtistView.h @@ -83,6 +83,9 @@ public: public slots: void onItemActivated( const QModelIndex& index ); +signals: + void modelChanged(); + protected: virtual void startDrag( Qt::DropActions supportedActions ); virtual void resizeEvent( QResizeEvent* event ); @@ -107,7 +110,6 @@ private: OverlayWidget* m_overlay; TreeModel* m_model; TreeProxyModel* m_proxyModel; -// PlaylistItemDelegate* m_delegate; AnimatedSpinner* m_loadingSpinner; bool m_updateContextView; From 172a4a8d776e8e984d6846f8804d194f2519dc5e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:34:19 +0200 Subject: [PATCH 173/433] * TrackView now uses LoadingSpinner and new OverlayWidget. --- src/libtomahawk/playlist/TrackView.cpp | 7 +++---- src/libtomahawk/playlist/TrackView.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index 5049758b9..3b55f288e 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -52,7 +52,7 @@ TrackView::TrackView( QWidget* parent ) , m_delegate( 0 ) , m_header( new TrackHeader( this ) ) , m_overlay( new OverlayWidget( this ) ) - , m_loadingSpinner( new AnimatedSpinner( this ) ) + , m_loadingSpinner( new LoadingSpinner( this ) ) , m_resizing( false ) , m_dragging( false ) , m_updateContextView( true ) @@ -147,9 +147,6 @@ TrackView::setPlayableModel( PlayableModel* model ) m_proxyModel->setSourcePlayableModel( m_model ); } - connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); - connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); - connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) ); connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); @@ -168,6 +165,8 @@ TrackView::setPlayableModel( PlayableModel* model ) setHeaderHidden( false ); setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); } + + emit modelChanged(); } diff --git a/src/libtomahawk/playlist/TrackView.h b/src/libtomahawk/playlist/TrackView.h index 7ff314656..634139f3a 100644 --- a/src/libtomahawk/playlist/TrackView.h +++ b/src/libtomahawk/playlist/TrackView.h @@ -80,6 +80,7 @@ public slots: signals: void itemActivated( const QModelIndex& index ); + void modelChanged(); protected: virtual void resizeEvent( QResizeEvent* event ); From 713b0769298d77465dd96939ae284f925ad0bf43 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:35:29 +0200 Subject: [PATCH 174/433] * WhatsHotWidget uses new TreeModel API. --- src/libtomahawk/widgets/WhatsHotWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index 5fadd8bc1..0af38cfee 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -263,7 +263,7 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat TreeModel* artistsModel = new TreeModel( ui->artistsViewLeft ); artistsModel->setMode( InfoSystemMode ); - artistsModel->setColumnStyle( TreeModel::AllColumns ); + artistsModel->setStyle( PlayableModel::Collection ); m_artistModels[ chartId ] = artistsModel; From 16736a2afd322808419434039cd965932aafb24e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:35:51 +0200 Subject: [PATCH 175/433] * RelatedArtistsContext uses new TreeModel API. --- src/libtomahawk/context/pages/RelatedArtistsContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp index 8d58719a0..eab2c7d2a 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp @@ -35,7 +35,7 @@ RelatedArtistsContext::RelatedArtistsContext() m_relatedView->setGuid( "RelatedArtistsContext" ); m_relatedView->setUpdatesContextView( false ); m_relatedModel = new TreeModel( m_relatedView ); - m_relatedModel->setColumnStyle( TreeModel::TrackOnly ); + m_relatedModel->setStyle( TreeModel::Large ); m_relatedView->setTreeModel( m_relatedModel ); m_relatedView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_relatedView->setSortingEnabled( false ); From c6ba3bcc159dabe33f375640fa4ddc98eb653d6c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 21:41:25 +0200 Subject: [PATCH 176/433] * CollectionFlatModel is obsolete now. --- src/libtomahawk/CMakeLists.txt | 1 - src/libtomahawk/ViewManager.cpp | 5 +- src/libtomahawk/ViewManager.h | 1 - .../playlist/CollectionFlatModel.cpp | 141 ------------------ .../playlist/CollectionFlatModel.h | 72 --------- .../widgets/infowidgets/SourceInfoWidget.cpp | 1 - 6 files changed, 2 insertions(+), 219 deletions(-) delete mode 100644 src/libtomahawk/playlist/CollectionFlatModel.cpp delete mode 100644 src/libtomahawk/playlist/CollectionFlatModel.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index ab645e2cb..efaa52ea7 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -52,7 +52,6 @@ set( libGuiSources playlist/TreeItemDelegate.cpp playlist/CollectionProxyModel.cpp playlist/CollectionProxyModelPlaylistInterface.cpp - playlist/CollectionFlatModel.cpp playlist/CollectionView.cpp playlist/PlaylistModel.cpp playlist/PlaylistProxyModel.cpp diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 0a738b6e6..5aff3ac1c 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -28,7 +28,6 @@ #include "topbar/TopBar.h" #include "TreeModel.h" -#include "CollectionFlatModel.h" #include "CollectionView.h" #include "PlaylistModel.h" #include "PlaylistView.h" @@ -280,7 +279,7 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) ViewPage* shown = 0; if ( m_currentMode == PlaylistModes::Flat ) { - CollectionView* view; +/* CollectionView* view; if ( !m_collectionViews.contains( collection ) || m_collectionViews.value( collection ).isNull() ) { view = new CollectionView(); @@ -297,7 +296,7 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) } shown = view; - setPage( view ); + setPage( view );*/ } if ( m_currentMode == PlaylistModes::Tree ) diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index 98cfb5299..78df072ac 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -39,7 +39,6 @@ class AlbumInfoWidget; class ArtistInfoWidget; class ArtistView; class CollectionModel; -class CollectionFlatModel; class CollectionView; class ContextWidget; class PlaylistModel; diff --git a/src/libtomahawk/playlist/CollectionFlatModel.cpp b/src/libtomahawk/playlist/CollectionFlatModel.cpp deleted file mode 100644 index 746d3c7d1..000000000 --- a/src/libtomahawk/playlist/CollectionFlatModel.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionFlatModel.h" - -#include "database/Database.h" -#include "SourceList.h" -#include "PlayableItem.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - - -CollectionFlatModel::CollectionFlatModel( QObject* parent ) - : PlayableModel( parent ) -{ -} - - -CollectionFlatModel::~CollectionFlatModel() -{ -} - - -void -CollectionFlatModel::addCollections( const QList< collection_ptr >& collections ) -{ - foreach( const collection_ptr& col, collections ) - { - addCollection( col ); - } - - // we are waiting for some to load - if( !m_loadingCollections.isEmpty() ) - emit loadingStarted(); -} - - -void -CollectionFlatModel::addCollection( const collection_ptr& collection, bool sendNotifications ) -{ - qDebug() << Q_FUNC_INFO << collection->name() - << collection->source()->id() - << collection->source()->userName(); - - if ( sendNotifications ) - emit loadingStarted(); - - DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( collection ); - connect( cmd, SIGNAL( tracks( QList, QVariant ) ), - SLOT( onTracksAdded( QList ) ), Qt::QueuedConnection ); - - Database::instance()->enqueue( QSharedPointer( cmd ) ); - - m_loadingCollections << collection.data(); - - if ( collection->source()->isLocal() ) - setTitle( tr( "My Collection" ) ); - else - setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) ); -} - - -void -CollectionFlatModel::addFilteredCollection( const collection_ptr& collection, unsigned int amount, DatabaseCommand_AllTracks::SortOrder order ) -{ - qDebug() << Q_FUNC_INFO << collection->name() - << collection->source()->id() - << collection->source()->userName() - << amount << order; - - DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( collection ); - cmd->setLimit( amount ); - cmd->setSortOrder( order ); - cmd->setSortDescending( true ); - - connect( cmd, SIGNAL( tracks( QList, QVariant ) ), - SLOT( onTracksAdded( QList ) ), Qt::QueuedConnection ); - - Database::instance()->enqueue( QSharedPointer( cmd ) ); -} - - -void -CollectionFlatModel::onTracksAdded( const QList& tracks ) -{ - qDebug() << Q_FUNC_INFO << tracks.count() << rowCount( QModelIndex() ); - - if ( !m_loadingCollections.isEmpty() && sender() && qobject_cast< Collection* >( sender() ) ) - { - // we are keeping track and are called as a slot - m_loadingCollections.removeAll( qobject_cast< Collection* >( sender() ) ); - } - - append( tracks ); - - if ( m_loadingCollections.isEmpty() ) - emit loadingFinished(); -} - - -void -CollectionFlatModel::onTracksRemoved( const QList& tracks ) -{ - QList t = tracks; - for ( int i = rowCount( QModelIndex() ); i >= 0 && t.count(); i-- ) - { - QModelIndex idx = index( i, 0, QModelIndex() ); - PlayableItem* item = itemFromIndex( idx ); - if ( !item ) - continue; - - int j = 0; - foreach ( const query_ptr& query, t ) - { - if ( item->query().data() == query.data() ) - { - remove( idx ); - t.removeAt( j ); - break; - } - - j++; - } - } -} diff --git a/src/libtomahawk/playlist/CollectionFlatModel.h b/src/libtomahawk/playlist/CollectionFlatModel.h deleted file mode 100644 index d158196de..000000000 --- a/src/libtomahawk/playlist/CollectionFlatModel.h +++ /dev/null @@ -1,72 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONFLATMODEL_H -#define COLLECTIONFLATMODEL_H - -#include -#include -#include - -#include "Typedefs.h" -#include "PlayableModel.h" -#include "Query.h" -#include "Source.h" -#include "PlaylistInterface.h" - -#include "database/DatabaseCommand_AllTracks.h" - -#include "DllMacro.h" - -class QMetaData; - -class DLLEXPORT CollectionFlatModel : public PlayableModel -{ -Q_OBJECT - -public: - explicit CollectionFlatModel( QObject* parent = 0 ); - ~CollectionFlatModel(); - - virtual int trackCount() const { return rowCount( QModelIndex() ) + m_tracksToAdd.count(); } - - void addCollections( const QList< Tomahawk::collection_ptr >& collections ); - void addCollection( const Tomahawk::collection_ptr& collection, bool sendNotifications = true ); - void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllTracks::SortOrder order ); - -signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - - void loadingStarted(); - void loadingFinished(); - void trackCountChanged( unsigned int tracks ); - -private slots: - void onTracksAdded( const QList& tracks ); - void onTracksRemoved( const QList& tracks ); - -private: - QMap< Tomahawk::collection_ptr, QPair< int, int > > m_collectionRows; - QList m_tracksToAdd; - // just to keep track of what we are waiting to be loaded - QList m_loadingCollections; -}; - -#endif // COLLECTIONFLATMODEL_H diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp index ebc46a80a..eee985c53 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp @@ -23,7 +23,6 @@ #include "ViewManager.h" #include "playlist/AlbumModel.h" -#include "playlist/CollectionFlatModel.h" #include "playlist/RecentlyAddedModel.h" #include "playlist/RecentlyPlayedModel.h" From 811cd200d09a2aee3ff5c333e525bdc0527ae680 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:08:58 +0200 Subject: [PATCH 177/433] * Support item-sizes & adding various item_ptr's with templating in PlayableModel. --- src/libtomahawk/playlist/PlayableModel.cpp | 135 ++++++++++++++++----- src/libtomahawk/playlist/PlayableModel.h | 18 ++- 2 files changed, 124 insertions(+), 29 deletions(-) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index 00036d987..e717ab084 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -288,6 +288,11 @@ PlayableModel::data( const QModelIndex& index, int role ) const return m_style; } + if ( role == Qt::SizeHintRole && !m_itemSize.isEmpty() ) + { + return m_itemSize; + } + if ( !entry->query().isNull() ) { return queryData( entry->query()->displayQuery(), index.column(), role ); @@ -571,59 +576,48 @@ PlayableModel::queries() const } +template void -PlayableModel::append( const Tomahawk::query_ptr& query ) +PlayableModel::insertInternal( const T& item, int row ) { - insert( query, rowCount( QModelIndex() ) ); -} - - -void -PlayableModel::append( const QList< Tomahawk::query_ptr >& queries ) -{ - insert( queries, rowCount( QModelIndex() ) ); -} - - -void -PlayableModel::insert( const Tomahawk::query_ptr& query, int row ) -{ - if ( query.isNull() ) + if ( item.isNull() ) return; - QList< Tomahawk::query_ptr > ql; - ql << query; + QList< T > list; + list << item; - insert( ql, row ); + insertInternal( list, row ); } +template void -PlayableModel::insert( const QList< Tomahawk::query_ptr >& queries, int row ) +PlayableModel::insertInternal( const QList< T >& items, int row ) { - if ( !queries.count() ) + if ( !items.count() ) { emit trackCountChanged( rowCount( QModelIndex() ) ); + emit itemCountChanged( rowCount( QModelIndex() ) ); return; } int c = row; QPair< int, int > crows; crows.first = c; - crows.second = c + queries.count() - 1; + crows.second = c + items.count() - 1; emit beginInsertRows( QModelIndex(), crows.first, crows.second ); int i = 0; PlayableItem* plitem; - foreach( const query_ptr& query, queries ) + foreach( const T& item, items ) { - plitem = new PlayableItem( query, m_rootItem, row + i ); + plitem = new PlayableItem( item, m_rootItem, row + i ); plitem->index = createIndex( row + i, 0, plitem ); i++; - if ( query->id() == currentItemUuid() ) - setCurrentItem( plitem->index ); +/* if ( item->id() == currentItemUuid() ) + setCurrentItem( plitem->index );*/ connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -744,7 +738,10 @@ PlayableModel::setStyle( PlayableModel::PlayableItemStyle style ) Qt::Alignment PlayableModel::columnAlignment( int column ) const { - switch( column ) + if ( !m_headerStyle.contains( m_style ) ) + return Qt::AlignLeft; + + switch( m_headerStyle[ m_style ].at( column ) ) { case Age: case AlbumPos: @@ -798,3 +795,87 @@ PlayableModel::itemFromIndex( const QModelIndex& index ) const return m_rootItem; } } + + +void +PlayableModel::append( const Tomahawk::artist_ptr& artist ) +{ + insert( artist, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const Tomahawk::album_ptr& album ) +{ + insert( album, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const Tomahawk::query_ptr& query ) +{ + insert( query, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const QList< Tomahawk::artist_ptr >& artists ) +{ + insert( artists, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const QList< Tomahawk::album_ptr >& albums ) +{ + insert( albums, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::append( const QList< Tomahawk::query_ptr >& queries ) +{ + insert( queries, rowCount( QModelIndex() ) ); +} + + +void +PlayableModel::insert( const Tomahawk::artist_ptr& artist, int row ) +{ + insertInternal( artist, row ); +} + + +void +PlayableModel::insert( const Tomahawk::album_ptr& album, int row ) +{ + insertInternal( album, row ); +} + + +void +PlayableModel::insert( const Tomahawk::query_ptr& query, int row ) +{ + insertInternal( query, row ); +} + + +void +PlayableModel::insert( const QList< Tomahawk::artist_ptr >& artists, int row ) +{ + insertInternal( artists, row ); +} + + +void +PlayableModel::insert( const QList< Tomahawk::album_ptr >& albums, int row ) +{ + insertInternal( albums, row ); +} + + +void +PlayableModel::insert( const QList< Tomahawk::query_ptr >& queries, int row ) +{ + insertInternal( queries, row ); +} diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index c529850e6..425496abf 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -112,6 +112,8 @@ public: QList< Tomahawk::query_ptr > queries() const; void updateDetailedInfo( const QModelIndex& index ); + + void setItemSize( const QSize& size ) { m_itemSize = size; } signals: void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); @@ -129,12 +131,18 @@ public slots: virtual void clear(); virtual void append( const QList< Tomahawk::query_ptr >& queries ); + virtual void append( const QList< Tomahawk::artist_ptr >& artists ); + virtual void append( const QList< Tomahawk::album_ptr >& albums ); virtual void append( const Tomahawk::query_ptr& query ); - virtual void append( const Tomahawk::artist_ptr& artist ) { Q_UNUSED( artist ); } - virtual void append( const Tomahawk::album_ptr& album ) { Q_UNUSED( album ); } + virtual void append( const Tomahawk::artist_ptr& artist ); + virtual void append( const Tomahawk::album_ptr& album ); virtual void insert( const QList< Tomahawk::query_ptr >& queries, int row = 0 ); + virtual void insert( const QList< Tomahawk::artist_ptr >& artists, int row = 0 ); + virtual void insert( const QList< Tomahawk::album_ptr >& albums, int row = 0 ); virtual void insert( const Tomahawk::query_ptr& query, int row = 0 ); + virtual void insert( const Tomahawk::artist_ptr& artist, int row = 0 ); + virtual void insert( const Tomahawk::album_ptr& album, int row = 0 ); virtual void remove( int row, bool moreToCome = false ); virtual void remove( const QModelIndex& index, bool moreToCome = false ); @@ -156,11 +164,17 @@ private slots: void onPlaybackStopped(); private: + template + void insertInternal( const QList< T >& items, int row ); + template + void insertInternal( const T& item, int row ); + Qt::Alignment columnAlignment( int column ) const; PlayableItem* m_rootItem; QPersistentModelIndex m_currentIndex; Tomahawk::QID m_currentUuid; + QSize m_itemSize; bool m_readOnly; From bc982f0ca5bee51a3e44077876e0e071491cc4ce Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:09:37 +0200 Subject: [PATCH 178/433] * AlbumModel now inherits from PlayableModel. --- src/libtomahawk/playlist/AlbumModel.cpp | 230 ++---------------------- src/libtomahawk/playlist/AlbumModel.h | 63 +------ 2 files changed, 12 insertions(+), 281 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumModel.cpp b/src/libtomahawk/playlist/AlbumModel.cpp index 649e92258..d7d82f98a 100644 --- a/src/libtomahawk/playlist/AlbumModel.cpp +++ b/src/libtomahawk/playlist/AlbumModel.cpp @@ -35,8 +35,7 @@ using namespace Tomahawk; AlbumModel::AlbumModel( QObject* parent ) - : QAbstractItemModel( parent ) - , m_rootItem( new PlayableItem( 0, this ) ) + : PlayableModel( parent ) , m_overwriteOnAdd( false ) { } @@ -44,197 +43,6 @@ AlbumModel::AlbumModel( QObject* parent ) AlbumModel::~AlbumModel() { - delete m_rootItem; -} - - -QModelIndex -AlbumModel::index( int row, int column, const QModelIndex& parent ) const -{ - if ( !m_rootItem || row < 0 || column < 0 ) - return QModelIndex(); - - PlayableItem* parentItem = itemFromIndex( parent ); - PlayableItem* childItem = parentItem->children.value( row ); - if ( !childItem ) - return QModelIndex(); - - return createIndex( row, column, childItem ); -} - - -int -AlbumModel::rowCount( const QModelIndex& parent ) const -{ - if ( parent.column() > 0 ) - return 0; - - PlayableItem* parentItem = itemFromIndex( parent ); - if ( !parentItem ) - return 0; - - return parentItem->children.count(); -} - - -int -AlbumModel::columnCount( const QModelIndex& parent ) const -{ - Q_UNUSED( parent ); - return 1; -} - - -QModelIndex -AlbumModel::parent( const QModelIndex& child ) const -{ - PlayableItem* entry = itemFromIndex( child ); - if ( !entry ) - return QModelIndex(); - - PlayableItem* parentEntry = entry->parent(); - if ( !parentEntry ) - return QModelIndex(); - - PlayableItem* grandparentEntry = parentEntry->parent(); - if ( !grandparentEntry ) - return QModelIndex(); - - int row = grandparentEntry->children.indexOf( parentEntry ); - return createIndex( row, 0, parentEntry ); -} - - -QVariant -AlbumModel::data( const QModelIndex& index, int role ) const -{ - if ( role == Qt::SizeHintRole ) - return m_itemSize; - - PlayableItem* entry = itemFromIndex( index ); - if ( !entry ) - return QVariant(); - - if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole ) - return QVariant(); - - QString name; - if ( !entry->album().isNull() ) - name = entry->album()->name(); - else if ( !entry->artist().isNull() ) - name = entry->artist()->name(); - - switch( index.column() ) - { - case 0: - return name; - break; - } - - return QVariant(); -} - - -QVariant -AlbumModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - QStringList headers; - headers << tr( "Album" ); - if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 ) - { - return headers.at( section ); - } - - return QVariant(); -} - - -Qt::ItemFlags -AlbumModel::flags( const QModelIndex& index ) const -{ - Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index ); - - if ( index.isValid() && index.column() == 0 ) - return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; - else - return defaultFlags; -} - - -QStringList -AlbumModel::mimeTypes() const -{ - QStringList types; - types << "application/tomahawk.query.list"; - return types; -} - - -QMimeData* -AlbumModel::mimeData( const QModelIndexList &indexes ) const -{ - QByteArray queryData; - QDataStream queryStream( &queryData, QIODevice::WriteOnly ); - - bool isAlbumData = true; - foreach ( const QModelIndex& i, indexes ) - { - if ( i.column() > 0 ) - continue; - - QModelIndex idx = index( i.row(), 0, i.parent() ); - PlayableItem* item = itemFromIndex( idx ); - if ( item && !item->album().isNull() ) - { - const album_ptr& album = item->album(); - queryStream << album->artist()->name(); - queryStream << album->name(); - - isAlbumData = true; - } - else if ( item && !item->artist().isNull() ) - { - const artist_ptr& artist = item->artist(); - queryStream << artist->name(); - - isAlbumData = false; - } - } - - QMimeData* mimeData = new QMimeData; - mimeData->setData( isAlbumData ? "application/tomahawk.metadata.album" : "application/tomahawk.metadata.artist", queryData ); - - return mimeData; -} - - -void -AlbumModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( index.column() > 0 ) - return; - - PlayableItem* item = itemFromIndex( index ); - if ( item ) - { - emit beginRemoveRows( index.parent(), index.row(), index.row() ); - delete item; - emit endRemoveRows(); - } - - emit itemCountChanged( rowCount( QModelIndex() ) ); -} - - -void -AlbumModel::removeIndexes( const QList& indexes ) -{ - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } } @@ -254,7 +62,7 @@ AlbumModel::addCollection( const collection_ptr& collection, bool overwrite ) Database::instance()->enqueue( QSharedPointer( cmd ) ); - m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() ); + setTitle( tr( "All albums from %1" ).arg( collection->source()->friendlyName() ) ); if ( collection.isNull() ) { @@ -296,9 +104,9 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in Database::instance()->enqueue( QSharedPointer( cmd ) ); if ( !collection.isNull() ) - m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() ); + setTitle( tr( "All albums from %1" ).arg( collection->source()->friendlyName() ) ); else - m_title = tr( "All albums" ); + setTitle( tr( "All albums" ) ); emit loadingStarted(); } @@ -339,8 +147,8 @@ AlbumModel::addAlbums( const QList& albums ) PlayableItem* albumitem; foreach( const album_ptr& album, trimmedAlbums ) { - albumitem = new PlayableItem( album, m_rootItem ); - albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem ); + albumitem = new PlayableItem( album, rootItem() ); + albumitem->index = createIndex( rootItem()->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -385,8 +193,8 @@ AlbumModel::addArtists( const QList& artists ) PlayableItem* albumitem; foreach ( const artist_ptr& artist, trimmedArtists ) { - albumitem = new PlayableItem( artist, m_rootItem ); - albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem ); + albumitem = new PlayableItem( artist, rootItem() ); + albumitem->index = createIndex( rootItem()->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -414,8 +222,8 @@ AlbumModel::addQueries( const QList& queries ) PlayableItem* albumitem; foreach ( const query_ptr& query, queries ) { - albumitem = new PlayableItem( query, m_rootItem ); - albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem ); + albumitem = new PlayableItem( query, rootItem() ); + albumitem->index = createIndex( rootItem()->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } @@ -439,24 +247,6 @@ AlbumModel::onCollectionChanged() } -void -AlbumModel::clear() -{ - beginResetModel(); - delete m_rootItem; - m_rootItem = new PlayableItem( 0, this ); - endResetModel(); -} - - -void -AlbumModel::onDataChanged() -{ - PlayableItem* p = (PlayableItem*)sender(); - emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) ); -} - - PlayableItem* AlbumModel::findItem( const artist_ptr& artist ) const { diff --git a/src/libtomahawk/playlist/AlbumModel.h b/src/libtomahawk/playlist/AlbumModel.h index c7ea509ff..0c6413786 100644 --- a/src/libtomahawk/playlist/AlbumModel.h +++ b/src/libtomahawk/playlist/AlbumModel.h @@ -20,19 +20,19 @@ #ifndef ALBUMMODEL_H #define ALBUMMODEL_H -#include #include #include "Album.h" #include "PlaylistInterface.h" #include "database/DatabaseCommand_AllAlbums.h" +#include "PlayableModel.h" #include "DllMacro.h" class PlayableItem; class QMetaData; -class DLLEXPORT AlbumModel : public QAbstractItemModel +class DLLEXPORT AlbumModel : public PlayableModel { Q_OBJECT @@ -40,87 +40,28 @@ public: explicit AlbumModel( QObject* parent = 0 ); virtual ~AlbumModel(); - virtual QModelIndex index( int row, int column, const QModelIndex& parent ) const; - virtual QModelIndex parent( const QModelIndex& child ) const; - - virtual bool isReadOnly() const { return true; } - - virtual int trackCount() const { return rowCount( QModelIndex() ); } - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual int rowCount( const QModelIndex& parent ) const; - virtual int columnCount( const QModelIndex& parent ) const; - - virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; - virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; - - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; - virtual QStringList mimeTypes() const; - virtual Qt::ItemFlags flags( const QModelIndex& index ) const; - Tomahawk::collection_ptr collection() const { return m_collection; } - void clear(); void addCollection( const Tomahawk::collection_ptr& collection, bool overwrite = false ); void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order, bool overwrite = false ); - virtual QString title() const { return m_title; } - virtual QString description() const { return m_description; } - virtual void setTitle( const QString& title ) { m_title = title; } - virtual void setDescription( const QString& description ) { m_description = description; } - - QSize itemSize() const { return m_itemSize; } - void setItemSize( const QSize& size ) { m_itemSize = size; } - PlayableItem* findItem( const Tomahawk::artist_ptr& artist ) const; PlayableItem* findItem( const Tomahawk::album_ptr& album ) const; - PlayableItem* itemFromIndex( const QModelIndex& index ) const - { - if ( index.isValid() ) - return static_cast( index.internalPointer() ); - else - { - return m_rootItem; - } - } - public slots: - virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode /*mode*/ ) {} - virtual void setShuffled( bool /*shuffled*/ ) {} - void addAlbums( const QList& albums ); void addArtists( const QList& artists ); void addQueries( const QList& queries ); signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - - void itemCountChanged( unsigned int items ); - - void loadingStarted(); - void loadingFinished(); private slots: - void onDataChanged(); - void onSourceAdded( const Tomahawk::source_ptr& source ); void onCollectionChanged(); private: - QPersistentModelIndex m_currentIndex; - PlayableItem* m_rootItem; - - QString m_title; - QString m_description; bool m_overwriteOnAdd; - QSize m_itemSize; - Tomahawk::collection_ptr m_collection; }; From 6d057732b59e6d786ec43894960a6534ef25a09b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:09:58 +0200 Subject: [PATCH 179/433] * Support new AlbumModel API. --- src/libtomahawk/playlist/AlbumProxyModel.cpp | 6 +++--- src/libtomahawk/playlist/AlbumProxyModel.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumProxyModel.cpp b/src/libtomahawk/playlist/AlbumProxyModel.cpp index 528805662..29d4bbf45 100644 --- a/src/libtomahawk/playlist/AlbumProxyModel.cpp +++ b/src/libtomahawk/playlist/AlbumProxyModel.cpp @@ -37,7 +37,7 @@ AlbumProxyModel::AlbumProxyModel( QObject* parent ) setSortCaseSensitivity( Qt::CaseInsensitive ); setDynamicSortFilter( true ); - setSourceAlbumModel( 0 ); + setSourcePlayableModel( 0 ); } @@ -51,7 +51,7 @@ AlbumProxyModel::setSourceModel( QAbstractItemModel* sourceModel ) void -AlbumProxyModel::setSourceAlbumModel( AlbumModel* sourceModel ) +AlbumProxyModel::setSourcePlayableModel( PlayableModel* sourceModel ) { m_model = sourceModel; @@ -125,7 +125,7 @@ AlbumProxyModel::removeIndex( const QModelIndex& index ) if ( index.column() > 0 ) return; - sourceModel()->removeIndex( mapToSource( index ) ); + sourceModel()->remove( mapToSource( index ) ); } diff --git a/src/libtomahawk/playlist/AlbumProxyModel.h b/src/libtomahawk/playlist/AlbumProxyModel.h index c0973caaa..f93356811 100644 --- a/src/libtomahawk/playlist/AlbumProxyModel.h +++ b/src/libtomahawk/playlist/AlbumProxyModel.h @@ -23,7 +23,7 @@ #include #include "PlaylistInterface.h" -#include "playlist/AlbumModel.h" +#include "playlist/PlayableModel.h" #include "DllMacro.h" @@ -35,8 +35,8 @@ public: explicit AlbumProxyModel( QObject* parent = 0 ); virtual ~AlbumProxyModel() {} - virtual AlbumModel* sourceModel() const { return m_model; } - virtual void setSourceAlbumModel( AlbumModel* sourceModel ); + virtual PlayableModel* sourceModel() const { return m_model; } + virtual void setSourcePlayableModel( PlayableModel* sourceModel ); virtual void setSourceModel( QAbstractItemModel* sourceModel ); virtual int albumCount() const { return rowCount( QModelIndex() ); } @@ -56,7 +56,7 @@ protected: bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; private: - AlbumModel* m_model; + PlayableModel* m_model; Tomahawk::playlistinterface_ptr m_playlistInterface; }; From fee2f3a01b2b5a2cec4709f11549ae718bfbe814 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:10:27 +0200 Subject: [PATCH 180/433] * AlbumView now uses a PlayableModel internally. --- src/libtomahawk/playlist/AlbumView.cpp | 8 ++++---- src/libtomahawk/playlist/AlbumView.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 321d1d54b..11b12d8af 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -33,6 +33,7 @@ #include "PlayableItem.h" #include "AlbumItemDelegate.h" #include "AlbumModel.h" +#include "PlayableModel.h" #include "ContextMenu.h" #include "ViewManager.h" #include "utils/Logger.h" @@ -115,14 +116,14 @@ AlbumView::setModel( QAbstractItemModel* model ) void -AlbumView::setAlbumModel( AlbumModel* model ) +AlbumView::setPlayableModel( PlayableModel* model ) { m_inited = false; m_model = model; if ( m_proxyModel ) { - m_proxyModel->setSourceAlbumModel( m_model ); + m_proxyModel->setSourcePlayableModel( m_model ); m_proxyModel->sort( 0 ); } @@ -202,8 +203,7 @@ AlbumView::layoutItems() #endif int rectWidth = contentsRect().width() - scrollbar - 3; int itemWidth = 160; - QSize itemSize = m_proxyModel->data( QModelIndex(), Qt::SizeHintRole ).toSize(); - Q_UNUSED( itemSize ); // looks obsolete +// QSize itemSize = m_proxyModel->data( QModelIndex(), Qt::SizeHintRole ).toSize(); int itemsPerRow = qMax( 1, qFloor( rectWidth / itemWidth ) ); // int rightSpacing = rectWidth - ( itemsPerRow * ( itemSize.width() + 16 ) ); diff --git a/src/libtomahawk/playlist/AlbumView.h b/src/libtomahawk/playlist/AlbumView.h index 0a231f002..a1f256d8b 100644 --- a/src/libtomahawk/playlist/AlbumView.h +++ b/src/libtomahawk/playlist/AlbumView.h @@ -34,9 +34,9 @@ namespace Tomahawk class ContextMenu; }; -class AlbumModel; class AnimatedSpinner; class AlbumItemDelegate; +class PlayableModel; class DLLEXPORT AlbumView : public QListView, public Tomahawk::ViewPage { @@ -48,13 +48,13 @@ public: void setProxyModel( AlbumProxyModel* model ); - AlbumModel* model() const { return m_model; } + PlayableModel* model() const { return m_model; } AlbumProxyModel* proxyModel() const { return m_proxyModel; } bool autoFitItems() const { return m_autoFitItems; } void setAutoFitItems( bool b ) { m_autoFitItems = b; } - void setAlbumModel( AlbumModel* model ); + void setPlayableModel( PlayableModel* model ); void setModel( QAbstractItemModel* model ); virtual QWidget* widget() { return this; } @@ -91,7 +91,7 @@ private slots: void layoutItems(); private: - AlbumModel* m_model; + PlayableModel* m_model; AlbumProxyModel* m_proxyModel; AlbumItemDelegate* m_delegate; AnimatedSpinner* m_loadingSpinner; From b14985bf8180f694e2bd05669f930918990cd987 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:10:52 +0200 Subject: [PATCH 181/433] * Style fix in CustomPlaylistView. --- src/libtomahawk/playlist/CustomPlaylistView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/CustomPlaylistView.cpp b/src/libtomahawk/playlist/CustomPlaylistView.cpp index 7ba352c03..388dceea6 100644 --- a/src/libtomahawk/playlist/CustomPlaylistView.cpp +++ b/src/libtomahawk/playlist/CustomPlaylistView.cpp @@ -103,7 +103,7 @@ void CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks ) { bool changed = false; - QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks, changed); + QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks, changed ); if ( !changed ) return; From 790120836d14e5ad76f66eee6b64e2cd26311834 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:11:17 +0200 Subject: [PATCH 182/433] * NewReleasesWidget now uses PlayableModels. --- src/libtomahawk/widgets/NewReleasesWidget.cpp | 10 +++++----- src/libtomahawk/widgets/NewReleasesWidget.h | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/widgets/NewReleasesWidget.cpp b/src/libtomahawk/widgets/NewReleasesWidget.cpp index 68636a8f1..6c91799c7 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.cpp +++ b/src/libtomahawk/widgets/NewReleasesWidget.cpp @@ -186,13 +186,12 @@ NewReleasesWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData request if ( type == "albums" ) { - loader->setType( ChartDataLoader::Album ); loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), this, SLOT( newReleasesLoaded( Tomahawk::ChartDataLoader*, QList ) ) ); - AlbumModel* albumModel = new AlbumModel( ui->albumsView ); + PlayableModel* albumModel = new PlayableModel( ui->albumsView ); m_albumModels[ releaseId ] = albumModel; @@ -344,12 +343,13 @@ NewReleasesWidget::parseNode( QStandardItem* parentItem, const QString &label, c void -NewReleasesWidget::setLeftViewAlbums( AlbumModel* model ) +NewReleasesWidget::setLeftViewAlbums( PlayableModel* model ) { - ui->albumsView->setAlbumModel( model ); + ui->albumsView->setPlayableModel( model ); ui->albumsView->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel } + void NewReleasesWidget::newReleasesLoaded( ChartDataLoader* loader, const QList< album_ptr >& albums ) { @@ -357,7 +357,7 @@ NewReleasesWidget::newReleasesLoaded( ChartDataLoader* loader, const QList< albu Q_ASSERT( m_albumModels.contains( chartId ) ); if ( m_albumModels.contains( chartId ) ) - m_albumModels[ chartId ]->addAlbums( albums ); + m_albumModels[ chartId ]->append( albums ); m_workers.remove( loader ); loader->deleteLater(); diff --git a/src/libtomahawk/widgets/NewReleasesWidget.h b/src/libtomahawk/widgets/NewReleasesWidget.h index c26e4eefc..333266852 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.h +++ b/src/libtomahawk/widgets/NewReleasesWidget.h @@ -40,6 +40,7 @@ class PlaylistModel; class OverlayWidget; class TreeProxyModel; class AlbumModel; +class PlayableModel; namespace Ui { @@ -95,7 +96,7 @@ private slots: private: void setLeftViewArtists( TreeModel* artistModel ); - void setLeftViewAlbums( AlbumModel* albumModel ); + void setLeftViewAlbums( PlayableModel* albumModel ); void setLeftViewTracks( PlaylistModel* trackModel ); @@ -113,7 +114,7 @@ private: QSet< Tomahawk::ChartDataLoader* > m_workers; // Cache our model data - QHash< QString, AlbumModel* > m_albumModels; + QHash< QString, PlayableModel* > m_albumModels; QString m_queueItemToShow; QSet< QString > m_queuedFetches; QTimer* m_timer; From 1c4fabed2b2cd218c9f178e40b8faaa6fc5d975d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:11:48 +0200 Subject: [PATCH 183/433] * WelcomeWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/WelcomeWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/WelcomeWidget.cpp b/src/libtomahawk/widgets/WelcomeWidget.cpp index 75b8f1846..e7162802a 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.cpp +++ b/src/libtomahawk/widgets/WelcomeWidget.cpp @@ -73,7 +73,7 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->tracksView->setPlaylistModel( m_tracksModel ); m_recentAlbumsModel = new AlbumModel( ui->additionsView ); - ui->additionsView->setAlbumModel( m_recentAlbumsModel ); + ui->additionsView->setPlayableModel( m_recentAlbumsModel ); ui->additionsView->proxyModel()->sort( -1 ); connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); From 98de149eec70d5136c5eea0a8b2d17151ad528a2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:12:10 +0200 Subject: [PATCH 184/433] * TrackInfoWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp | 8 ++++---- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index dbc0244ba..98635bc59 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -23,7 +23,7 @@ #include "ViewManager.h" #include "SourceList.h" -#include "playlist/AlbumModel.h" +#include "playlist/PlayableModel.h" #include "audio/AudioEngine.h" #include "utils/TomahawkUtilsGui.h" @@ -83,8 +83,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->lyricsView->setPalette( p ); // ui->similarTracksLabel->setPalette( p ); - m_relatedTracksModel = new AlbumModel( ui->similarTracksView ); - ui->similarTracksView->setAlbumModel( m_relatedTracksModel ); + m_relatedTracksModel = new PlayableModel( ui->similarTracksView ); + ui->similarTracksView->setPlayableModel( m_relatedTracksModel ); ui->similarTracksView->proxyModel()->sort( -1 ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); @@ -209,7 +209,7 @@ TrackInfoWidget::onSimilarArtistsLoaded() void TrackInfoWidget::onSimilarTracksLoaded() { - m_relatedTracksModel->addQueries( m_query->similarTracks() ); + m_relatedTracksModel->append( m_query->similarTracks() ); } diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h index 1a1f7c341..93c82b61d 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h @@ -39,7 +39,7 @@ #include "DllMacro.h" #include "Typedefs.h" -class AlbumModel; +class PlayableModel; namespace Ui { @@ -88,7 +88,7 @@ private: Tomahawk::query_ptr m_query; Tomahawk::artist_ptr m_artist; - AlbumModel* m_relatedTracksModel; + PlayableModel* m_relatedTracksModel; QString m_title; QPixmap m_pixmap; }; From 2a4f2d380239a8eeecab08508e86366efdfbf697 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:12:23 +0200 Subject: [PATCH 185/433] * SourceInfoWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp index eee985c53..f1fa9b307 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp @@ -63,7 +63,7 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* ui->historyView->setPlaylistModel( m_historyModel ); m_recentAlbumModel = new AlbumModel( ui->recentAlbumView ); - ui->recentAlbumView->setAlbumModel( m_recentAlbumModel ); + ui->recentAlbumView->setPlayableModel( m_recentAlbumModel ); ui->recentAlbumView->proxyModel()->sort( -1 ); onCollectionChanged(); From bf9052bb1baee3462414a777556b6df95cefc7b6 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:12:50 +0200 Subject: [PATCH 186/433] * ArtistInfoWidget uses new AlbumView/AlbumModel API. --- .../widgets/infowidgets/ArtistInfoWidget.cpp | 15 +++++++-------- .../widgets/infowidgets/ArtistInfoWidget.h | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index d2c9c068c..2cd534f88 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -23,6 +23,7 @@ #include "audio/AudioEngine.h" #include "playlist/TrackHeader.h" +#include "playlist/PlayableModel.h" #include "playlist/TreeModel.h" #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" @@ -59,13 +60,11 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* TomahawkUtils::unmarginLayout( ui->layoutWidget2->layout() ); TomahawkUtils::unmarginLayout( ui->albumHeader->layout() ); - m_albumsModel = new AlbumModel( ui->albums ); - ui->albums->setAlbumModel( m_albumsModel ); + m_albumsModel = new PlayableModel( ui->albums ); + ui->albums->setPlayableModel( m_albumsModel ); - m_relatedModel = new AlbumModel( ui->relatedArtists ); -// m_relatedModel->setColumnStyle( TreeModel::TrackOnly ); - ui->relatedArtists->setAlbumModel( m_relatedModel ); -// ui->relatedArtists->setSortingEnabled( false ); + m_relatedModel = new PlayableModel( ui->relatedArtists ); + ui->relatedArtists->setPlayableModel( m_relatedModel ); ui->relatedArtists->proxyModel()->sort( -1 ); m_topHitsModel = new PlaylistModel( ui->topHits ); @@ -191,7 +190,7 @@ ArtistInfoWidget::onAlbumsFound( const QList& albums, Model { Q_UNUSED( mode ); - m_albumsModel->addAlbums( albums ); + m_albumsModel->append( albums ); } @@ -207,7 +206,7 @@ ArtistInfoWidget::onTracksFound( const QList& queries, Mode void ArtistInfoWidget::onSimilarArtistsLoaded() { - m_relatedModel->addArtists( m_artist->similarArtists() ); + m_relatedModel->append( m_artist->similarArtists() ); } diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index 097cbca8b..9d3588ed0 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -39,7 +39,7 @@ #include "DllMacro.h" -class AlbumModel; +class PlayableModel; class PlaylistModel; class OverlayButton; @@ -106,8 +106,8 @@ private: Tomahawk::artist_ptr m_artist; - AlbumModel* m_relatedModel; - AlbumModel* m_albumsModel; + PlayableModel* m_relatedModel; + PlayableModel* m_albumsModel; PlaylistModel* m_topHitsModel; Tomahawk::playlistinterface_ptr m_plInterface; From 088ff603397f2195705388683f8a1a67fdef76e8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:13:09 +0200 Subject: [PATCH 187/433] * AlbumInfoWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp | 8 ++++---- src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 99aebceac..4b6b5a6eb 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -25,7 +25,7 @@ #include "ViewManager.h" #include "database/Database.h" #include "playlist/TreeModel.h" -#include "playlist/AlbumModel.h" +#include "playlist/PlayableModel.h" #include "Source.h" #include "database/DatabaseCommand_AllTracks.h" @@ -50,8 +50,8 @@ AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* par TomahawkUtils::unmarginLayout( ui->verticalLayout ); TomahawkUtils::unmarginLayout( ui->verticalLayout_2 ); - m_albumsModel = new AlbumModel( ui->albumsView ); - ui->albumsView->setAlbumModel( m_albumsModel ); + m_albumsModel = new PlayableModel( ui->albumsView ); + ui->albumsView->setPlayableModel( m_albumsModel ); m_tracksModel = new TreeModel( ui->tracksView ); m_tracksModel->setMode( Mixed ); @@ -183,7 +183,7 @@ AlbumInfoWidget::gotAlbums( const QList& albums ) if ( al.contains( m_album ) ) al.removeAll( m_album ); - m_albumsModel->addAlbums( al ); + m_albumsModel->append( al ); } diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h index 43bcfbfa3..4234914ec 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h @@ -39,7 +39,7 @@ #include "DllMacro.h" #include "Typedefs.h" -class AlbumModel; +class PlayableModel; class TreeModel; class OverlayButton; @@ -104,7 +104,7 @@ private: Tomahawk::album_ptr m_album; - AlbumModel* m_albumsModel; + PlayableModel* m_albumsModel; TreeModel* m_tracksModel; QString m_title; From cd198db31d3c135da4ae1a7d47ef2de188628352 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:13:32 +0200 Subject: [PATCH 188/433] * WhatsHotWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/WhatsHotWidget.cpp | 11 +++++------ src/libtomahawk/widgets/WhatsHotWidget.h | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index 0af38cfee..dc3692ad1 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -34,6 +34,7 @@ #include "audio/AudioEngine.h" #include "dynamic/GeneratorInterface.h" +#include "playlist/PlayableModel.h" #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" @@ -272,13 +273,12 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat } else if ( type == "albums" ) { - loader->setType( ChartDataLoader::Album ); loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), this, SLOT( chartAlbumsLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ) ); - AlbumModel* albumModel = new AlbumModel( ui->albumsView ); + PlayableModel* albumModel = new PlayableModel( ui->albumsView ); m_albumModels[ chartId ] = albumModel; @@ -287,7 +287,6 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat } else if ( type == "tracks" ) { - loader->setType( ChartDataLoader::Track ); loader->setData( returnedData[ "tracks" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); @@ -452,9 +451,9 @@ WhatsHotWidget::parseNode( QStandardItem* parentItem, const QString &label, cons void -WhatsHotWidget::setLeftViewAlbums( AlbumModel* model ) +WhatsHotWidget::setLeftViewAlbums( PlayableModel* model ) { - ui->albumsView->setAlbumModel( model ); + ui->albumsView->setPlayableModel( model ); ui->albumsView->proxyModel()->sort( -1 ); // disable sorting, must be called after artistsViewLeft->setTreeModel ui->stackLeft->setCurrentIndex( 2 ); } @@ -522,7 +521,7 @@ WhatsHotWidget::chartAlbumsLoaded( ChartDataLoader* loader, const QList< album_p Q_ASSERT( m_albumModels.contains( chartId ) ); if ( m_albumModels.contains( chartId ) ) - m_albumModels[ chartId ]->addAlbums( albums ); + m_albumModels[ chartId ]->append( albums ); m_workers.remove( loader ); loader->deleteLater(); diff --git a/src/libtomahawk/widgets/WhatsHotWidget.h b/src/libtomahawk/widgets/WhatsHotWidget.h index d192fad92..372ba0aa3 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.h +++ b/src/libtomahawk/widgets/WhatsHotWidget.h @@ -38,7 +38,7 @@ class TreeModel; class PlaylistModel; class OverlayWidget; class TreeProxyModel; -class AlbumModel; +class PlayableModel; namespace Ui { @@ -96,7 +96,7 @@ private slots: private: void setLeftViewArtists( TreeModel* artistModel ); - void setLeftViewAlbums( AlbumModel* albumModel ); + void setLeftViewAlbums( PlayableModel* albumModel ); void setLeftViewTracks( PlaylistModel* trackModel ); @@ -114,7 +114,7 @@ private: QSet< Tomahawk::ChartDataLoader* > m_workers; // Cache our model data - QHash< QString, AlbumModel* > m_albumModels; + QHash< QString, PlayableModel* > m_albumModels; QHash< QString, TreeModel* > m_artistModels; QHash< QString, PlaylistModel* > m_trackModels; QString m_queueItemToShow; From a2f8a2ae117108d782c7e6bc025c2bc9e2ad4133 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:13:53 +0200 Subject: [PATCH 189/433] * SocialPlaylistWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/SocialPlaylistWidget.cpp | 7 ++++--- src/libtomahawk/widgets/SocialPlaylistWidget.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp index 8f0eb5202..cd42b8dfe 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.cpp +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.cpp @@ -23,6 +23,7 @@ #include "database/DatabaseCommand_LoadDynamicPlaylist.h" #include "database/Database.h" #include "SourceList.h" +#include "PlayableModel.h" #include "dynamic/GeneratorInterface.h" #include "dynamic/database/DatabaseGenerator.h" #include "utils/Logger.h" @@ -71,8 +72,8 @@ SocialPlaylistWidget::SocialPlaylistWidget ( QWidget* parent ) m_topForeignTracksModel->setStyle( PlayableModel::Short ); ui->newTracksView->overlay()->setEnabled( false ); - m_popularNewAlbumsModel = new AlbumModel( ui->newAlbumsView ); - ui->newAlbumsView->setAlbumModel( m_popularNewAlbumsModel ); + m_popularNewAlbumsModel = new PlayableModel( ui->newAlbumsView ); + ui->newAlbumsView->setPlayableModel( m_popularNewAlbumsModel ); // TODO run the genericselect command // m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime ); /* @@ -139,7 +140,7 @@ SocialPlaylistWidget::popularAlbumsFetched( QList< album_ptr > albums ) { m_popularNewAlbumsModel->clear(); - m_popularNewAlbumsModel->addAlbums( albums ); + m_popularNewAlbumsModel->append( albums ); } diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.h b/src/libtomahawk/widgets/SocialPlaylistWidget.h index 0afb813da..14ae0b7f4 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.h +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.h @@ -38,7 +38,7 @@ #include "Album.h" #include "Query.h" -class AlbumModel; +class PlayableModel; class PlaylistModel; class TreeModel; @@ -81,7 +81,7 @@ private: Ui_SocialPlaylistWidget *ui; PlaylistModel* m_topForeignTracksModel; - AlbumModel* m_popularNewAlbumsModel; + PlayableModel* m_popularNewAlbumsModel; QString m_title; QString m_description; From 54612b351225c2010a6f10b618599f87568e77fe Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:14:12 +0200 Subject: [PATCH 190/433] * SearchWidget uses new AlbumView/AlbumModel API. --- src/libtomahawk/widgets/SearchWidget.cpp | 18 +++++++++--------- src/libtomahawk/widgets/SearchWidget.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libtomahawk/widgets/SearchWidget.cpp b/src/libtomahawk/widgets/SearchWidget.cpp index 1ad389472..047229cc3 100644 --- a/src/libtomahawk/widgets/SearchWidget.cpp +++ b/src/libtomahawk/widgets/SearchWidget.cpp @@ -25,7 +25,7 @@ #include "SourceList.h" #include "ViewManager.h" -#include "playlist/AlbumModel.h" +#include "playlist/PlayableModel.h" #include "playlist/PlaylistModel.h" #include "widgets/OverlayWidget.h" #include "utils/AnimatedSpinner.h" @@ -47,11 +47,11 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent ) ui->resultsView->overlay()->setEnabled( false ); ui->resultsView->sortByColumn( PlaylistModel::Score, Qt::DescendingOrder ); - m_albumsModel = new AlbumModel( ui->albumView ); - ui->albumView->setAlbumModel( m_albumsModel ); + m_albumsModel = new PlayableModel( ui->albumView ); + ui->albumView->setPlayableModel( m_albumsModel ); - m_artistsModel = new AlbumModel( ui->artistView ); - ui->artistView->setAlbumModel( m_artistsModel ); + m_artistsModel = new PlayableModel( ui->artistView ); + ui->artistView->setPlayableModel( m_artistsModel ); ui->artistView->proxyModel()->sort( -1 ); ui->albumView->proxyModel()->sort( -1 ); @@ -134,22 +134,22 @@ SearchWidget::onResultsFound( const QList& results ) albums << result->album(); } - m_artistsModel->addArtists( artists ); - m_albumsModel->addAlbums( albums ); + m_artistsModel->append( artists ); + m_albumsModel->append( albums ); } void SearchWidget::onAlbumsFound( const QList& albums ) { - m_albumsModel->addAlbums( albums ); + m_albumsModel->append( albums ); } void SearchWidget::onArtistsFound( const QList& artists ) { - m_artistsModel->addArtists( artists ); + m_artistsModel->append( artists ); } diff --git a/src/libtomahawk/widgets/SearchWidget.h b/src/libtomahawk/widgets/SearchWidget.h index b7d026740..70f942bfe 100644 --- a/src/libtomahawk/widgets/SearchWidget.h +++ b/src/libtomahawk/widgets/SearchWidget.h @@ -31,7 +31,7 @@ #include "DllMacro.h" class QPushButton; -class AlbumModel; +class PlayableModel; class PlaylistModel; namespace Ui @@ -77,8 +77,8 @@ private: QString m_search; - AlbumModel* m_artistsModel; - AlbumModel* m_albumsModel; + PlayableModel* m_artistsModel; + PlayableModel* m_albumsModel; PlaylistModel* m_resultsModel; QList< Tomahawk::query_ptr > m_queries; }; From a62a9d50fe38b8ad289abac7370487f9ef4baa11 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 31 May 2012 23:14:28 +0200 Subject: [PATCH 191/433] * ViewManager uses new AlbumView/AlbumModel API. --- src/libtomahawk/ViewManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 5aff3ac1c..0d309eb96 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -103,7 +103,7 @@ ViewManager::ViewManager( QObject* parent ) m_superAlbumView = new AlbumView(); m_superAlbumModel = new AlbumModel( m_superAlbumView ); - m_superAlbumView->setAlbumModel( m_superAlbumModel ); + m_superAlbumView->setPlayableModel( m_superAlbumModel ); m_stack->setContentsMargins( 0, 0, 0, 0 ); m_widget->setContentsMargins( 0, 0, 0, 0 ); @@ -328,7 +328,7 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) { aview = new AlbumView(); AlbumModel* amodel = new AlbumModel( aview ); - aview->setAlbumModel( amodel ); + aview->setPlayableModel( amodel ); amodel->addCollection( collection ); m_collectionAlbumViews.insert( collection, aview ); From 14f66474718ed1a1dee3ba3388cd515e9fb1e22f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:29:40 +0200 Subject: [PATCH 192/433] * Removed obsolete proxy models and their interfaces. --- src/libtomahawk/CMakeLists.txt | 5 - src/libtomahawk/playlist/AlbumProxyModel.cpp | 154 ------------------ src/libtomahawk/playlist/AlbumProxyModel.h | 64 -------- .../AlbumProxyModelPlaylistInterface.cpp | 101 ------------ .../AlbumProxyModelPlaylistInterface.h | 78 --------- .../playlist/PlaylistProxyModel.cpp | 40 ----- src/libtomahawk/playlist/PlaylistProxyModel.h | 38 ----- .../PlaylistProxyModelPlaylistInterface.cpp | 35 ---- .../PlaylistProxyModelPlaylistInterface.h | 43 ----- .../QueueProxyModelPlaylistInterface.cpp | 51 ------ .../QueueProxyModelPlaylistInterface.h | 46 ------ 11 files changed, 655 deletions(-) delete mode 100644 src/libtomahawk/playlist/AlbumProxyModel.cpp delete mode 100644 src/libtomahawk/playlist/AlbumProxyModel.h delete mode 100644 src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp delete mode 100644 src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h delete mode 100644 src/libtomahawk/playlist/PlaylistProxyModel.cpp delete mode 100644 src/libtomahawk/playlist/PlaylistProxyModel.h delete mode 100644 src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp delete mode 100644 src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h delete mode 100644 src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp delete mode 100644 src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index efaa52ea7..60cfd43c9 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -54,12 +54,9 @@ set( libGuiSources playlist/CollectionProxyModelPlaylistInterface.cpp playlist/CollectionView.cpp playlist/PlaylistModel.cpp - playlist/PlaylistProxyModel.cpp - playlist/PlaylistProxyModelPlaylistInterface.cpp playlist/PlaylistView.cpp playlist/PlaylistItemDelegate.cpp playlist/QueueProxyModel.cpp - playlist/QueueProxyModelPlaylistInterface.cpp playlist/QueueView.cpp playlist/PlayableModel.cpp playlist/PlayableProxyModel.cpp @@ -67,8 +64,6 @@ set( libGuiSources playlist/TrackView.cpp playlist/TrackHeader.cpp playlist/AlbumModel.cpp - playlist/AlbumProxyModel.cpp - playlist/AlbumProxyModelPlaylistInterface.cpp playlist/AlbumItemDelegate.cpp playlist/AlbumView.cpp playlist/ArtistView.cpp diff --git a/src/libtomahawk/playlist/AlbumProxyModel.cpp b/src/libtomahawk/playlist/AlbumProxyModel.cpp deleted file mode 100644 index 29d4bbf45..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModel.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "AlbumProxyModel.h" - -#include - -#include "AlbumProxyModelPlaylistInterface.h" -#include "Artist.h" -#include "PlayableItem.h" -#include "Query.h" -#include "Source.h" -#include "utils/Logger.h" - - -AlbumProxyModel::AlbumProxyModel( QObject* parent ) - : QSortFilterProxyModel( parent ) - , m_model( 0 ) -{ - setFilterCaseSensitivity( Qt::CaseInsensitive ); - setSortCaseSensitivity( Qt::CaseInsensitive ); - setDynamicSortFilter( true ); - - setSourcePlayableModel( 0 ); -} - - -void -AlbumProxyModel::setSourceModel( QAbstractItemModel* sourceModel ) -{ - Q_UNUSED( sourceModel ); - qDebug() << "Explicitly use setSourceAlbumModel instead"; - Q_ASSERT( false ); -} - - -void -AlbumProxyModel::setSourcePlayableModel( PlayableModel* sourceModel ) -{ - m_model = sourceModel; - - if ( m_model && m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); - - QSortFilterProxyModel::setSourceModel( sourceModel ); -} - - -bool -AlbumProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const -{ - if ( filterRegExp().isEmpty() ) - return true; - - PlayableItem* pi = sourceModel()->itemFromIndex( sourceModel()->index( sourceRow, 0, sourceParent ) ); - if ( !pi ) - return false; - - const Tomahawk::album_ptr& q = pi->album(); - - QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); - - bool found = true; - foreach( const QString& s, sl ) - { - if ( !q->name().contains( s, Qt::CaseInsensitive ) && !q->artist()->name().contains( s, Qt::CaseInsensitive ) ) - { - found = false; - } - } - - return found; -} - - -bool -AlbumProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const -{ - PlayableItem* p1 = sourceModel()->itemFromIndex( left ); - PlayableItem* p2 = sourceModel()->itemFromIndex( right ); - - if ( !p1 ) - return true; - if ( !p2 ) - return false; - - if ( p1->album().isNull() || p1->album()->artist().isNull() ) - return true; - - if ( p2->album().isNull() || p2->album()->artist().isNull() ) - return false; - - if ( p1->album()->artist()->name() == p2->album()->artist()->name() ) - { - return QString::localeAwareCompare( p1->album()->name(), p2->album()->name() ) < 0; - } - - return QString::localeAwareCompare( p1->album()->artist()->name(), p2->album()->artist()->name() ) < 0; -} - - -void -AlbumProxyModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( !sourceModel() ) - return; - if ( index.column() > 0 ) - return; - - sourceModel()->remove( mapToSource( index ) ); -} - - -void -AlbumProxyModel::removeIndexes( const QList& indexes ) -{ - if ( !sourceModel() ) - return; - - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } -} - - -Tomahawk::playlistinterface_ptr -AlbumProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::AlbumProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/AlbumProxyModel.h b/src/libtomahawk/playlist/AlbumProxyModel.h deleted file mode 100644 index f93356811..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModel.h +++ /dev/null @@ -1,64 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef ALBUMPROXYMODEL_H -#define ALBUMPROXYMODEL_H - -#include - -#include "PlaylistInterface.h" -#include "playlist/PlayableModel.h" - -#include "DllMacro.h" - -class DLLEXPORT AlbumProxyModel : public QSortFilterProxyModel -{ -Q_OBJECT - -public: - explicit AlbumProxyModel( QObject* parent = 0 ); - virtual ~AlbumProxyModel() {} - - virtual PlayableModel* sourceModel() const { return m_model; } - virtual void setSourcePlayableModel( PlayableModel* sourceModel ); - virtual void setSourceModel( QAbstractItemModel* sourceModel ); - - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual void emitFilterChanged( const QString &pattern ) { emit filterChanged( pattern ); } - - virtual Tomahawk::playlistinterface_ptr playlistInterface(); - -signals: - void filterChanged( const QString& filter ); - -protected: - bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; - bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; - -private: - PlayableModel* m_model; - - Tomahawk::playlistinterface_ptr m_playlistInterface; -}; - -#endif // ALBUMPROXYMODEL_H diff --git a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp deleted file mode 100644 index 3ede9ef7f..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "AlbumProxyModelPlaylistInterface.h" - -#include "AlbumProxyModel.h" -#include "Artist.h" -#include "Query.h" -#include "Source.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -AlbumProxyModelPlaylistInterface::AlbumProxyModelPlaylistInterface( AlbumProxyModel *proxyModel ) - : Tomahawk::PlaylistInterface() - , m_proxyModel( proxyModel ) - , m_repeatMode( PlaylistModes::NoRepeat ) - , m_shuffled( false ) -{ -} - - -AlbumProxyModelPlaylistInterface::~AlbumProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} - - -QList< Tomahawk::query_ptr > -AlbumProxyModelPlaylistInterface::tracks() -{ - Q_ASSERT( FALSE ); - QList queries; - return queries; -} - - -int -AlbumProxyModelPlaylistInterface::unfilteredTrackCount() const -{ - return ( m_proxyModel.isNull() ? 0 : m_proxyModel.data()->sourceModel()->rowCount( QModelIndex() ) ); -} - - -int -AlbumProxyModelPlaylistInterface::trackCount() const -{ - return ( m_proxyModel.isNull() ? 0 : m_proxyModel.data()->rowCount( QModelIndex() ) ); -} - - -Tomahawk::result_ptr -AlbumProxyModelPlaylistInterface::currentItem() const -{ - return Tomahawk::result_ptr(); -} - - -QString -AlbumProxyModelPlaylistInterface::filter() const -{ - return ( m_proxyModel.isNull() ? QString() : m_proxyModel.data()->filterRegExp().pattern() ); -} - - -void -AlbumProxyModelPlaylistInterface::setFilter( const QString& pattern ) -{ - qDebug() << Q_FUNC_INFO; - - if ( m_proxyModel.isNull() ) - return; - - m_proxyModel.data()->setFilterRegExp( pattern ); - m_proxyModel.data()->emitFilterChanged( pattern ); -} - - -Tomahawk::result_ptr -AlbumProxyModelPlaylistInterface::siblingItem( int itemsAway ) -{ - Q_UNUSED( itemsAway ); - qDebug() << Q_FUNC_INFO; - return Tomahawk::result_ptr( 0 ); -} diff --git a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h deleted file mode 100644 index c04791306..000000000 --- a/src/libtomahawk/playlist/AlbumProxyModelPlaylistInterface.h +++ /dev/null @@ -1,78 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef ALBUMPROXYMODELPLAYLISTINTERFACE_H -#define ALBUMPROXYMODELPLAYLISTINTERFACE_H - -#include "PlaylistInterface.h" -#include "playlist/AlbumModel.h" - -#include "DllMacro.h" - -class AlbumProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT AlbumProxyModelPlaylistInterface : public Tomahawk::PlaylistInterface -{ -Q_OBJECT - -public: - explicit AlbumProxyModelPlaylistInterface( AlbumProxyModel *proxyModel ); - virtual ~AlbumProxyModelPlaylistInterface(); - - virtual QList tracks(); - - virtual int unfilteredTrackCount() const; - virtual int trackCount() const; - - virtual bool hasNextItem() { return true; } - virtual Tomahawk::result_ptr currentItem() const; - virtual Tomahawk::result_ptr siblingItem( int direction ); - - virtual QString filter() const; - virtual void setFilter( const QString& pattern ); - - virtual Tomahawk::PlaylistModes::RepeatMode repeatMode() const { return m_repeatMode; } - virtual bool shuffled() const { return m_shuffled; } - virtual Tomahawk::PlaylistModes::ViewMode viewMode() const { return Tomahawk::PlaylistModes::Album; } - -signals: - void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); - void shuffleModeChanged( bool enabled ); - - void trackCountChanged( unsigned int tracks ); - void sourceTrackCountChanged( unsigned int tracks ); - - void nextTrackReady(); - -public slots: - virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode mode ) { m_repeatMode = mode; emit repeatModeChanged( mode ); } - virtual void setShuffled( bool enabled ) { m_shuffled = enabled; emit shuffleModeChanged( enabled ); } - -private: - QWeakPointer< AlbumProxyModel > m_proxyModel; - PlaylistModes::RepeatMode m_repeatMode; - bool m_shuffled; -}; - -} //ns - -#endif // ALBUMPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/PlaylistProxyModel.cpp b/src/libtomahawk/playlist/PlaylistProxyModel.cpp deleted file mode 100644 index b9d7ccb7e..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModel.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "PlaylistProxyModel.h" - -#include "PlaylistProxyModelPlaylistInterface.h" -#include "utils/Logger.h" - - -PlaylistProxyModel::PlaylistProxyModel( QObject* parent ) - : PlayableProxyModel( parent ) -{ -} - -Tomahawk::playlistinterface_ptr -PlaylistProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::PlaylistProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/PlaylistProxyModel.h b/src/libtomahawk/playlist/PlaylistProxyModel.h deleted file mode 100644 index 49adf1534..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModel.h +++ /dev/null @@ -1,38 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef PLAYLISTPROXYMODEL_H -#define PLAYLISTPROXYMODEL_H - -#include "PlayableProxyModel.h" - -#include "DllMacro.h" - -class DLLEXPORT PlaylistProxyModel : public PlayableProxyModel -{ -Q_OBJECT - -public: - explicit PlaylistProxyModel( QObject* parent = 0 ); - virtual ~PlaylistProxyModel() {} - - virtual Tomahawk::playlistinterface_ptr playlistInterface(); -}; - -#endif // PLAYLISTPROXYMODEL_H diff --git a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp deleted file mode 100644 index ce06675d2..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "PlaylistProxyModelPlaylistInterface.h" - -#include "PlaylistProxyModel.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -PlaylistProxyModelPlaylistInterface::PlaylistProxyModelPlaylistInterface( PlaylistProxyModel *proxyModel ) - : PlayableProxyModelPlaylistInterface( proxyModel ) -{ -} - -PlaylistProxyModelPlaylistInterface::~PlaylistProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} diff --git a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h deleted file mode 100644 index 29888c0bf..000000000 --- a/src/libtomahawk/playlist/PlaylistProxyModelPlaylistInterface.h +++ /dev/null @@ -1,43 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef PLAYLISTPROXYMODELPLAYLISTINTERFACE_H -#define PLAYLISTPROXYMODELPLAYLISTINTERFACE_H - -#include "PlayableProxyModelPlaylistInterface.h" - -#include "DllMacro.h" - -class PlaylistProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT PlaylistProxyModelPlaylistInterface : public PlayableProxyModelPlaylistInterface -{ -Q_OBJECT - -public: - explicit PlaylistProxyModelPlaylistInterface( PlaylistProxyModel *proxyModel ); - virtual ~PlaylistProxyModelPlaylistInterface(); -}; - -} //ns - -#endif // PLAYLISTPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp deleted file mode 100644 index 25f94cd78..000000000 --- a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "QueueProxyModelPlaylistInterface.h" - -#include "QueueProxyModel.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -QueueProxyModelPlaylistInterface::QueueProxyModelPlaylistInterface( QueueProxyModel *proxyModel ) - : PlaylistProxyModelPlaylistInterface( proxyModel ) -{ -} - - -QueueProxyModelPlaylistInterface::~QueueProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} - - -Tomahawk::result_ptr -QueueProxyModelPlaylistInterface::siblingItem( int itemsAway ) -{ - if ( m_proxyModel.isNull() ) - return Tomahawk::result_ptr(); - - m_proxyModel.data()->setCurrentIndex( QModelIndex() ); - Tomahawk::result_ptr res = PlaylistProxyModelPlaylistInterface::siblingItem( itemsAway ); - - m_proxyModel.data()->remove( m_proxyModel.data()->currentIndex() ); - - return res; -} diff --git a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h deleted file mode 100644 index 12540f2ff..000000000 --- a/src/libtomahawk/playlist/QueueProxyModelPlaylistInterface.h +++ /dev/null @@ -1,46 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef QUEUEPROXYMODELPLAYLISTINTERFACE_H -#define QUEUEPROXYMODELPLAYLISTINTERFACE_H - -#include "PlaylistProxyModelPlaylistInterface.h" - -#include "Result.h" -#include "DllMacro.h" - -class QueueProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT QueueProxyModelPlaylistInterface : public PlaylistProxyModelPlaylistInterface -{ -Q_OBJECT - -public: - explicit QueueProxyModelPlaylistInterface( QueueProxyModel *proxyModel ); - virtual ~QueueProxyModelPlaylistInterface(); - - virtual Tomahawk::result_ptr siblingItem( int itemsAway ); -}; - -} //ns - -#endif // QUEUEPROXYMODELPLAYLISTINTERFACE_H From d17783ef6e722279001d11f84238697e7fd8552a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:30:28 +0200 Subject: [PATCH 193/433] * PlayableProxyModel supports artist & album items. --- .../playlist/PlayableProxyModel.cpp | 163 +++++++++++++----- src/libtomahawk/playlist/PlayableProxyModel.h | 14 +- 2 files changed, 132 insertions(+), 45 deletions(-) diff --git a/src/libtomahawk/playlist/PlayableProxyModel.cpp b/src/libtomahawk/playlist/PlayableProxyModel.cpp index aec3abf87..783250f6c 100644 --- a/src/libtomahawk/playlist/PlayableProxyModel.cpp +++ b/src/libtomahawk/playlist/PlayableProxyModel.cpp @@ -43,6 +43,18 @@ PlayableProxyModel::PlayableProxyModel( QObject* parent ) } +bool +PlayableProxyModel::isLoading() const +{ + if ( m_model ) + { + return m_model->isLoading(); + } + + return false; +} + + void PlayableProxyModel::setSourceModel( QAbstractItemModel* model ) { @@ -55,10 +67,25 @@ PlayableProxyModel::setSourceModel( QAbstractItemModel* model ) void PlayableProxyModel::setSourcePlayableModel( PlayableModel* sourceModel ) { + if ( m_model ) + { + if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) + disconnect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), this, SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + + disconnect( m_model, SIGNAL( loadingStarted() ), this, SIGNAL( loadingStarted() ) ); + disconnect( m_model, SIGNAL( loadingFinished() ), this, SIGNAL( loadingFinished() ) ); + } + m_model = sourceModel; - if ( m_model && m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + if ( m_model ) + { + if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) + connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + + connect( m_model, SIGNAL( loadingStarted() ), SIGNAL( loadingStarted() ) ); + connect( m_model, SIGNAL( loadingFinished() ), SIGNAL( loadingFinished() ) ); + } QSortFilterProxyModel::setSourceModel( m_model ); } @@ -71,32 +98,69 @@ PlayableProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePa if ( !pi ) return false; - const Tomahawk::query_ptr& q = pi->query()->displayQuery(); - if ( q.isNull() ) // uh oh? filter out invalid queries i guess - return false; - - Tomahawk::result_ptr r; - if ( q->numResults() ) - r = q->results().first(); - - if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() ) - return false; - - if ( filterRegExp().isEmpty() ) - return true; - - QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); - foreach( QString s, sl ) + if ( pi->query() ) { - s = s.toLower(); - if ( !q->artist().toLower().contains( s ) && - !q->album().toLower().contains( s ) && - !q->track().toLower().contains( s ) ) - { + const Tomahawk::query_ptr& q = pi->query()->displayQuery(); + if ( q.isNull() ) // uh oh? filter out invalid queries i guess return false; + + Tomahawk::result_ptr r; + if ( q->numResults() ) + r = q->results().first(); + + if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() ) + return false; + + if ( filterRegExp().isEmpty() ) + return true; + + QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); + foreach( QString s, sl ) + { + s = s.toLower(); + if ( !q->artist().toLower().contains( s ) && + !q->album().toLower().contains( s ) && + !q->track().toLower().contains( s ) ) + { + return false; + } } } + const Tomahawk::album_ptr& al = pi->album(); + if ( al ) + { + QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); + + bool found = true; + foreach( const QString& s, sl ) + { + if ( !al->name().contains( s, Qt::CaseInsensitive ) && !al->artist()->name().contains( s, Qt::CaseInsensitive ) ) + { + found = false; + } + } + + return found; + } + + const Tomahawk::album_ptr& ar = pi->album(); + if ( ar ) + { + QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); + + bool found = true; + foreach( const QString& s, sl ) + { + if ( !ar->name().contains( s, Qt::CaseInsensitive ) && !ar->artist()->name().contains( s, Qt::CaseInsensitive ) ) + { + found = false; + } + } + + return found; + } + return true; } @@ -148,19 +212,8 @@ PlayableProxyModel::remove( const QList< QPersistentModelIndex >& indexes ) bool -PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const +PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const Tomahawk::query_ptr& q2 ) const { - PlayableItem* p1 = itemFromIndex( left ); - PlayableItem* p2 = itemFromIndex( right ); - - if ( !p1 ) - return true; - if ( !p2 ) - return false; - - const Tomahawk::query_ptr& q1 = p1->query()->displayQuery(); - const Tomahawk::query_ptr& q2 = p2->query()->displayQuery(); - const QString artist1 = q1->artistSortname(); const QString artist2 = q2->artistSortname(); const QString album1 = q1->albumSortname(); @@ -203,7 +256,7 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right id2 = (qint64)&q2; } - if ( left.column() == PlayableModel::Artist ) // sort by artist + if ( column == PlayableModel::Artist ) // sort by artist { if ( artist1 == artist2 ) { @@ -225,7 +278,7 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right return QString::localeAwareCompare( artist1, artist2 ) < 0; } - else if ( left.column() == PlayableModel::Album ) // sort by album + else if ( column == PlayableModel::Album ) // sort by album { if ( album1 == album2 ) { @@ -242,28 +295,28 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right return QString::localeAwareCompare( album1, album2 ) < 0; } - else if ( left.column() == PlayableModel::Bitrate ) // sort by bitrate + else if ( column == PlayableModel::Bitrate ) // sort by bitrate { if ( bitrate1 == bitrate2 ) return id1 < id2; return bitrate1 < bitrate2; } - else if ( left.column() == PlayableModel::Age ) // sort by mtime + else if ( column == PlayableModel::Age ) // sort by mtime { if ( mtime1 == mtime2 ) return id1 < id2; return mtime1 < mtime2; } - else if ( left.column() == PlayableModel::Filesize ) // sort by file size + else if ( column == PlayableModel::Filesize ) // sort by file size { if ( size1 == size2 ) return id1 < id2; return size1 < size2; } - else if ( left.column() == PlayableModel::AlbumPos ) // sort by album pos + else if ( column == PlayableModel::AlbumPos ) // sort by album pos { if ( discnumber1 != discnumber2 ) { @@ -275,9 +328,9 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right return albumpos1 < albumpos2; } } - - const QString& lefts = sourceModel()->data( left ).toString(); - const QString& rights = sourceModel()->data( right ).toString(); + + const QString& lefts = q1->track(); + const QString& rights = q2->track(); if ( lefts == rights ) return id1 < id2; @@ -285,6 +338,28 @@ PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right } +bool +PlayableProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const +{ + PlayableItem* p1 = itemFromIndex( left ); + PlayableItem* p2 = itemFromIndex( right ); + + if ( !p1 ) + return true; + if ( !p2 ) + return false; + + if ( p1->query() && p2->query() ) + { + const Tomahawk::query_ptr& q1 = p1->query()->displayQuery(); + const Tomahawk::query_ptr& q2 = p2->query()->displayQuery(); + return lessThan( left.column(), q1, q2 ); + } + + return QString::localeAwareCompare( sourceModel()->data( left ).toString(), sourceModel()->data( right ).toString() ) < 0; +} + + Tomahawk::playlistinterface_ptr PlayableProxyModel::playlistInterface() { diff --git a/src/libtomahawk/playlist/PlayableProxyModel.h b/src/libtomahawk/playlist/PlayableProxyModel.h index 34b63c145..2e2f2b662 100644 --- a/src/libtomahawk/playlist/PlayableProxyModel.h +++ b/src/libtomahawk/playlist/PlayableProxyModel.h @@ -39,6 +39,8 @@ public: virtual void setSourcePlayableModel( PlayableModel* sourceModel ); virtual void setSourceModel( QAbstractItemModel* model ); + virtual bool isLoading() const; + virtual QPersistentModelIndex currentIndex() const { return mapFromSource( m_model->currentItem() ); } virtual void setCurrentIndex( const QModelIndex& index ) { m_model->setCurrentItem( mapToSource( index ) ); } @@ -58,13 +60,23 @@ public: signals: void filterChanged( const QString& filter ); + void filteringStarted(); + void filteringFinished(); + + void loadingStarted(); + void loadingFinished(); + protected: virtual bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; virtual bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; + Tomahawk::playlistinterface_ptr m_playlistInterface; + +private: + virtual bool lessThan( int column, const Tomahawk::query_ptr& left, const Tomahawk::query_ptr& right ) const; + PlayableModel* m_model; bool m_showOfflineResults; - Tomahawk::playlistinterface_ptr m_playlistInterface; }; #endif // TRACKPROXYMODEL_H From 68bf96f92480f804b97846f520e92e81a797333c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:31:09 +0200 Subject: [PATCH 194/433] * PlaylistView uses a standard PlayableProxyModel now. --- src/libtomahawk/playlist/PlaylistView.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index fc748fd19..d42d1dfe2 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -22,7 +22,6 @@ #include #include -#include "playlist/PlaylistProxyModel.h" #include "widgets/OverlayWidget.h" #include "ViewManager.h" #include "utils/Logger.h" @@ -36,7 +35,7 @@ PlaylistView::PlaylistView( QWidget* parent ) : TrackView( parent ) , m_model( 0 ) { - setProxyModel( new PlaylistProxyModel( this ) ); + setProxyModel( new PlayableProxyModel( this ) ); connect( contextMenu(), SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); } From 0f6f58373e3c09a4c1539c5ad2e01c94fc7f76ae Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:31:33 +0200 Subject: [PATCH 195/433] * QueueProxyModel now inherits from PlayableProxyModel. --- src/libtomahawk/playlist/QueueProxyModel.cpp | 15 +-------------- src/libtomahawk/playlist/QueueProxyModel.h | 6 ++---- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/libtomahawk/playlist/QueueProxyModel.cpp b/src/libtomahawk/playlist/QueueProxyModel.cpp index b1821c68c..80c1d7dea 100644 --- a/src/libtomahawk/playlist/QueueProxyModel.cpp +++ b/src/libtomahawk/playlist/QueueProxyModel.cpp @@ -19,7 +19,6 @@ #include "QueueProxyModel.h" -#include "QueueProxyModelPlaylistInterface.h" #include "playlist/TrackView.h" #include "ViewManager.h" #include "utils/Logger.h" @@ -29,7 +28,7 @@ using namespace Tomahawk; QueueProxyModel::QueueProxyModel( TrackView* parent ) - : PlaylistProxyModel( parent ) + : PlayableProxyModel( parent ) { qDebug() << Q_FUNC_INFO; @@ -57,15 +56,3 @@ QueueProxyModel::onTrackCountChanged( unsigned int count ) if ( count == 0 ) ViewManager::instance()->hideQueue(); } - - -Tomahawk::playlistinterface_ptr -QueueProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::QueueProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/QueueProxyModel.h b/src/libtomahawk/playlist/QueueProxyModel.h index 8156d8df3..3ea2f9254 100644 --- a/src/libtomahawk/playlist/QueueProxyModel.h +++ b/src/libtomahawk/playlist/QueueProxyModel.h @@ -20,14 +20,14 @@ #ifndef QUEUEPROXYMODEL_H #define QUEUEPROXYMODEL_H -#include "PlaylistProxyModel.h" +#include "PlayableProxyModel.h" #include "DllMacro.h" class QMetaData; class TrackView; -class DLLEXPORT QueueProxyModel : public PlaylistProxyModel +class DLLEXPORT QueueProxyModel : public PlayableProxyModel { Q_OBJECT @@ -35,8 +35,6 @@ public: explicit QueueProxyModel( TrackView* parent = 0 ); virtual ~QueueProxyModel(); - virtual Tomahawk::playlistinterface_ptr playlistInterface(); - private slots: void onIndexActivated( const QModelIndex& index ); void onTrackCountChanged( unsigned int count ); From 644f6a714a10d0de082054bab4138426085cd9ff Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:32:15 +0200 Subject: [PATCH 196/433] * TreeProxyModel now inherits from PlayableProxyModel. --- src/libtomahawk/playlist/TreeProxyModel.cpp | 73 ++++----------------- src/libtomahawk/playlist/TreeProxyModel.h | 27 ++------ 2 files changed, 17 insertions(+), 83 deletions(-) diff --git a/src/libtomahawk/playlist/TreeProxyModel.cpp b/src/libtomahawk/playlist/TreeProxyModel.cpp index c8ffa0d43..8d181af65 100644 --- a/src/libtomahawk/playlist/TreeProxyModel.cpp +++ b/src/libtomahawk/playlist/TreeProxyModel.cpp @@ -32,52 +32,30 @@ TreeProxyModel::TreeProxyModel( QObject* parent ) - : QSortFilterProxyModel( parent ) + : PlayableProxyModel( parent ) , m_artistsFilterCmd( 0 ) , m_model( 0 ) { - setFilterCaseSensitivity( Qt::CaseInsensitive ); - setSortCaseSensitivity( Qt::CaseInsensitive ); - setDynamicSortFilter( true ); - - setSourceTreeModel( 0 ); -} - - -QPersistentModelIndex -TreeProxyModel::currentIndex() const -{ - if ( !m_model ) - return QPersistentModelIndex(); - - return mapFromSource( m_model->currentItem() ); } void -TreeProxyModel::setSourceModel( QAbstractItemModel* sourceModel ) +TreeProxyModel::setSourcePlayableModel( TreeModel* model ) { - Q_UNUSED( sourceModel ); - qDebug() << "Explicitly use setSourceTreeModel instead"; - Q_ASSERT( false ); -} - - -void -TreeProxyModel::setSourceTreeModel( TreeModel* sourceModel ) -{ - m_model = sourceModel; - - if ( m_model ) + if ( sourceModel() ) { - if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + disconnect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( onRowsInserted( QModelIndex, int, int ) ) ); + disconnect( m_model, SIGNAL( modelReset() ), this, SLOT( onModelReset() ) ); + } + PlayableProxyModel::setSourcePlayableModel( model ); + m_model = model; + + if ( sourceModel() ) + { connect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onRowsInserted( QModelIndex, int, int ) ) ); connect( m_model, SIGNAL( modelReset() ), SLOT( onModelReset() ) ); } - - QSortFilterProxyModel::setSourceModel( sourceModel ); } @@ -114,7 +92,7 @@ TreeProxyModel::onModelReset() void -TreeProxyModel::newFilterFromPlaylistInterface( const QString &pattern ) +TreeProxyModel::newFilterFromPlaylistInterface( const QString& pattern ) { emit filteringStarted(); @@ -339,33 +317,6 @@ TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) co } -void -TreeProxyModel::removeIndex( const QModelIndex& index ) -{ - qDebug() << Q_FUNC_INFO; - - if ( !sourceModel() ) - return; - if ( index.column() > 0 ) - return; - - sourceModel()->removeIndex( mapToSource( index ) ); -} - - -void -TreeProxyModel::removeIndexes( const QList& indexes ) -{ - if ( !sourceModel() ) - return; - - foreach( const QModelIndex& idx, indexes ) - { - removeIndex( idx ); - } -} - - QString TreeProxyModel::textForItem( PlayableItem* item ) const { diff --git a/src/libtomahawk/playlist/TreeProxyModel.h b/src/libtomahawk/playlist/TreeProxyModel.h index cf24f1973..bca8676b0 100644 --- a/src/libtomahawk/playlist/TreeProxyModel.h +++ b/src/libtomahawk/playlist/TreeProxyModel.h @@ -20,10 +20,9 @@ #ifndef TREEPROXYMODEL_H #define TREEPROXYMODEL_H -#include - #include "PlaylistInterface.h" #include "TreeModel.h" +#include "PlayableProxyModel.h" #include "DllMacro.h" @@ -34,7 +33,7 @@ namespace Tomahawk class TreeProxyModelPlaylistInterface; } -class DLLEXPORT TreeProxyModel : public QSortFilterProxyModel +class DLLEXPORT TreeProxyModel : public PlayableProxyModel { Q_OBJECT @@ -42,28 +41,13 @@ public: explicit TreeProxyModel( QObject* parent = 0 ); virtual ~TreeProxyModel() {} - virtual TreeModel* sourceModel() const { return m_model; } - virtual void setSourceTreeModel( TreeModel* sourceModel ); - virtual void setSourceModel( QAbstractItemModel* sourceModel ); + virtual void setSourcePlayableModel( TreeModel* model ); - virtual QPersistentModelIndex currentIndex() const; - virtual void setCurrentIndex( const QModelIndex& index ) { m_model->setCurrentItem( mapToSource( index ) ); } - - virtual void newFilterFromPlaylistInterface( const QString &pattern ); - - virtual void removeIndex( const QModelIndex& index ); - virtual void removeIndexes( const QList& indexes ); - - virtual int albumCount() const { return rowCount( QModelIndex() ); } - - virtual PlayableItem* itemFromIndex( const QModelIndex& index ) const { return sourceModel()->itemFromIndex( index ); } + virtual void newFilterFromPlaylistInterface( const QString& pattern ); virtual Tomahawk::playlistinterface_ptr playlistInterface(); signals: - void filterChanged( const QString& filter ); - void filteringStarted(); - void filteringFinished(); protected: bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; @@ -87,8 +71,7 @@ private: QList m_albumsFilter; DatabaseCommand_AllArtists* m_artistsFilterCmd; - QString m_filter; - + QString m_filter; TreeModel* m_model; Tomahawk::playlistinterface_ptr m_playlistInterface; From 7409f658745375e6cf7fc6fa4ceb0f81007a0956 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:32:50 +0200 Subject: [PATCH 197/433] * AlbumItemDelegate uses PlayableProxyModel now. --- src/libtomahawk/playlist/AlbumItemDelegate.cpp | 4 ++-- src/libtomahawk/playlist/AlbumItemDelegate.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index 7899cc7be..fc3b32d7f 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -36,7 +36,7 @@ #include #include "playlist/PlayableItem.h" -#include "playlist/AlbumProxyModel.h" +#include "playlist/PlayableProxyModel.h" #include "AlbumView.h" #include "ViewManager.h" #include "utils/AnimatedSpinner.h" @@ -48,7 +48,7 @@ namespace { }; -AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel* proxy ) +AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, PlayableProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) , m_view( parent ) , m_model( proxy ) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.h b/src/libtomahawk/playlist/AlbumItemDelegate.h index 1f38d76a9..81eace7cd 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.h +++ b/src/libtomahawk/playlist/AlbumItemDelegate.h @@ -25,13 +25,13 @@ #include "DllMacro.h" -class QTimeLine; namespace Tomahawk { class PixmapDelegateFader; } class QEvent; -class AlbumProxyModel; +class QTimeLine; +class PlayableProxyModel; class ImageButton; class DLLEXPORT AlbumItemDelegate : public QStyledItemDelegate @@ -39,7 +39,7 @@ class DLLEXPORT AlbumItemDelegate : public QStyledItemDelegate Q_OBJECT public: - AlbumItemDelegate( QAbstractItemView* parent = 0, AlbumProxyModel* proxy = 0 ); + AlbumItemDelegate( QAbstractItemView* parent = 0, PlayableProxyModel* proxy = 0 ); protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -68,7 +68,7 @@ private: QTimeLine* createTimeline( QTimeLine::Direction direction ); QAbstractItemView* m_view; - AlbumProxyModel* m_model; + PlayableProxyModel* m_model; mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects; mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_covers; From a42f19f07e7a7def4bc05e15f5e3a3d0e7c0723c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:33:17 +0200 Subject: [PATCH 198/433] * AlbumView uses PlayableProxyModel now. --- src/libtomahawk/playlist/AlbumView.cpp | 4 ++-- src/libtomahawk/playlist/AlbumView.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/AlbumView.cpp index 11b12d8af..963812375 100644 --- a/src/libtomahawk/playlist/AlbumView.cpp +++ b/src/libtomahawk/playlist/AlbumView.cpp @@ -74,7 +74,7 @@ AlbumView::AlbumView( QWidget* parent ) setStyleSheet( "QListView { background-color: #323435; }" ); setAutoFitItems( true ); - setProxyModel( new AlbumProxyModel( this ) ); + setProxyModel( new PlayableProxyModel( this ) ); /* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); m_overlay->setText( tr( "This collection doesn't have any recent albums." ) );*/ @@ -95,7 +95,7 @@ AlbumView::~AlbumView() void -AlbumView::setProxyModel( AlbumProxyModel* model ) +AlbumView::setProxyModel( PlayableProxyModel* model ) { m_proxyModel = model; m_delegate = new AlbumItemDelegate( this, m_proxyModel ); diff --git a/src/libtomahawk/playlist/AlbumView.h b/src/libtomahawk/playlist/AlbumView.h index a1f256d8b..3ca7b8d46 100644 --- a/src/libtomahawk/playlist/AlbumView.h +++ b/src/libtomahawk/playlist/AlbumView.h @@ -25,7 +25,7 @@ #include #include "ViewPage.h" -#include "AlbumProxyModel.h" +#include "PlayableProxyModel.h" #include "widgets/OverlayWidget.h" #include "DllMacro.h" @@ -46,10 +46,10 @@ public: explicit AlbumView( QWidget* parent = 0 ); ~AlbumView(); - void setProxyModel( AlbumProxyModel* model ); + void setProxyModel( PlayableProxyModel* model ); PlayableModel* model() const { return m_model; } - AlbumProxyModel* proxyModel() const { return m_proxyModel; } + PlayableProxyModel* proxyModel() const { return m_proxyModel; } bool autoFitItems() const { return m_autoFitItems; } void setAutoFitItems( bool b ) { m_autoFitItems = b; } @@ -92,7 +92,7 @@ private slots: private: PlayableModel* m_model; - AlbumProxyModel* m_proxyModel; + PlayableProxyModel* m_proxyModel; AlbumItemDelegate* m_delegate; AnimatedSpinner* m_loadingSpinner; OverlayWidget* m_overlay; From 657b4b18f87f2fa1cfb25d19feb9ea1e32658dc2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:33:39 +0200 Subject: [PATCH 199/433] * ArtistViw uses PlayableProxyModel now. --- src/libtomahawk/playlist/ArtistView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/ArtistView.cpp index 73387be7b..d21dccf4e 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/ArtistView.cpp @@ -132,7 +132,7 @@ ArtistView::setTreeModel( TreeModel* model ) if ( m_proxyModel ) { - m_proxyModel->setSourceTreeModel( model ); + m_proxyModel->setSourcePlayableModel( model ); m_proxyModel->sort( 0 ); } From 77b4e62918c8a9051a6e875cc5bddd93e407ed41 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:34:05 +0200 Subject: [PATCH 200/433] * OverlayWidget uses PlayableProxyModel now. --- src/libtomahawk/widgets/OverlayWidget.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index 5261fe986..745245df5 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -22,6 +22,7 @@ #include #include +#include "PlayableProxyModel.h" #include "utils/Logger.h" #define CORNER_ROUNDNESS 8.0 @@ -98,7 +99,7 @@ OverlayWidget::show( int timeoutSecs ) animation->setEndValue( 1.0 ); animation->start(); - if( timeoutSecs > 0 ) + if ( timeoutSecs > 0 ) m_timer.start( timeoutSecs * 1000 ); } @@ -129,7 +130,8 @@ OverlayWidget::shown() const void OverlayWidget::onViewChanged() { - if ( m_parent->model()->rowCount() ) + PlayableProxyModel* model = qobject_cast( m_parent->model() ); + if ( model && ( model->rowCount( QModelIndex() ) || model->isLoading() ) ) { hide(); } From 3467a9e47de27bb150e2ce22631550675a543b07 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:34:24 +0200 Subject: [PATCH 201/433] * Don't hook up TreeModel to InfoSystem anymore. --- src/libtomahawk/playlist/TreeModel.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libtomahawk/playlist/TreeModel.cpp b/src/libtomahawk/playlist/TreeModel.cpp index 2d0a7c575..5b54db35a 100644 --- a/src/libtomahawk/playlist/TreeModel.cpp +++ b/src/libtomahawk/playlist/TreeModel.cpp @@ -46,10 +46,6 @@ TreeModel::TreeModel( QObject* parent ) connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); } From d5d969e058f82aa15bc08feffda04660d734f714 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:34:48 +0200 Subject: [PATCH 202/433] * PlayableModel is set to be loading as default. --- src/libtomahawk/playlist/PlayableModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index e717ab084..3581ae92d 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -42,7 +42,7 @@ PlayableModel::PlayableModel( QObject* parent ) , m_rootItem( new PlayableItem( 0, this ) ) , m_readOnly( true ) , m_style( Detailed ) - , m_loading( false ) + , m_loading( true ) { connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection ); From 7ab04deb1293d23ce3f7181d3e75e9353b06be3f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 00:35:16 +0200 Subject: [PATCH 203/433] * No more AlbumProxyModel. --- src/libtomahawk/ViewManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 0d309eb96..f02e3316d 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -35,7 +35,6 @@ #include "PlayableModel.h" #include "ArtistView.h" #include "AlbumView.h" -#include "AlbumProxyModel.h" #include "AlbumModel.h" #include "SourceList.h" #include "TomahawkSettings.h" From c829752b7ef21d3cb792b014f68720c5c73f2847 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 01:05:36 +0200 Subject: [PATCH 204/433] * Switch to a pointing hand cursor when hovering an artist name in AlbumItemDelegate. --- src/libtomahawk/playlist/AlbumItemDelegate.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index fc3b32d7f..949b439fb 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -280,6 +280,11 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const if ( event->type() == QEvent::MouseMove ) { + if ( hoveringArtist ) + m_view->setCursor( Qt::PointingHandCursor ); + else + m_view->setCursor( Qt::ArrowCursor ); + foreach ( const QModelIndex& idx, m_playButton.keys() ) { if ( index != idx ) @@ -352,8 +357,12 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const return true; } + // reset mouse cursor. we switch to a pointing hand cursor when hovering an artist name + m_view->setCursor( Qt::ArrowCursor ); + if ( hoveringArtist ) { + if ( event->type() == QEvent::MouseButtonRelease ) { PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); From bb1800d27f9bd7ef31323c970ccb3204246ad8f9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 01:57:27 +0200 Subject: [PATCH 205/433] * Remove items from queue when they're played. --- src/libtomahawk/playlist/QueueView.cpp | 30 +++++++++++++++++++++++--- src/libtomahawk/playlist/QueueView.h | 3 +++ src/libtomahawk/playlist/QueueView.ui | 2 +- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 9062f081e..885909229 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -47,6 +47,12 @@ QueueView::QueueView( AnimatedSplitter* parent ) ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); ui->queue->overlay()->setEnabled( false ); + PlaylistModel* queueModel = new PlaylistModel( this ); + queueModel->setStyle( PlaylistModel::Short ); + ui->queue->setPlaylistModel( queueModel ); + queueModel->setReadOnly( false ); + + connect( queueModel, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( updateLabel() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); ui->toggleButton->installEventFilter( this ); @@ -119,9 +125,8 @@ QueueView::hide() connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); disconnect( ui->toggleButton, SIGNAL( resized( QPoint ) ), this, SIGNAL( resizeBy( QPoint ) ) ); - ui->toggleButton->setText( tr( "Show Queue" ) ); - AnimatedWidget::hide(); + updateLabel(); } @@ -132,8 +137,8 @@ QueueView::show() connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( hide() ) ); connect( ui->toggleButton, SIGNAL( resized( QPoint ) ), SIGNAL( resizeBy( QPoint ) ) ); - ui->toggleButton->setText( tr( "Hide Queue" ) ); AnimatedWidget::show(); + updateLabel(); } @@ -155,3 +160,22 @@ QueueView::onHidden( QWidget* widget, bool animated ) AnimatedWidget::onHidden( widget, animated ); } + + +void +QueueView::updateLabel() +{ + if ( isHidden() ) + { + const unsigned int c = queue()->model()->rowCount( QModelIndex() ); + + if ( c ) + ui->toggleButton->setText( tr( "Open Queue - %n item(s)", "", c ) ); + else + ui->toggleButton->setText( tr( "Open Queue" ) ); + } + else + { + ui->toggleButton->setText( tr( "Close Queue" ) ); + } +} diff --git a/src/libtomahawk/playlist/QueueView.h b/src/libtomahawk/playlist/QueueView.h index 49952dc37..9500264f0 100644 --- a/src/libtomahawk/playlist/QueueView.h +++ b/src/libtomahawk/playlist/QueueView.h @@ -57,6 +57,9 @@ public slots: protected: void changeEvent( QEvent* e ); +private slots: + void updateLabel(); + private: Ui::QueueView* ui; QTimer* m_dragTimer; diff --git a/src/libtomahawk/playlist/QueueView.ui b/src/libtomahawk/playlist/QueueView.ui index e9e318b12..fba21c5b1 100644 --- a/src/libtomahawk/playlist/QueueView.ui +++ b/src/libtomahawk/playlist/QueueView.ui @@ -38,7 +38,7 @@ true - Show Queue + Open Queue Qt::AlignCenter From f74e49b99bb299eb53b1bf72464826bcb8ec5c03 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 01:58:21 +0200 Subject: [PATCH 206/433] * Show how many items are currently in the queue. --- src/libtomahawk/playlist/QueueProxyModel.cpp | 24 ++++++++++++++++---- src/libtomahawk/playlist/QueueProxyModel.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/playlist/QueueProxyModel.cpp b/src/libtomahawk/playlist/QueueProxyModel.cpp index 80c1d7dea..e544eb645 100644 --- a/src/libtomahawk/playlist/QueueProxyModel.cpp +++ b/src/libtomahawk/playlist/QueueProxyModel.cpp @@ -19,10 +19,12 @@ #include "QueueProxyModel.h" +#include "audio/AudioEngine.h" #include "playlist/TrackView.h" +#include "PlayableItem.h" #include "ViewManager.h" -#include "utils/Logger.h" #include "Source.h" +#include "utils/Logger.h" using namespace Tomahawk; @@ -30,10 +32,9 @@ using namespace Tomahawk; QueueProxyModel::QueueProxyModel( TrackView* parent ) : PlayableProxyModel( parent ) { - qDebug() << Q_FUNC_INFO; - - connect( parent, SIGNAL( itemActivated( QModelIndex ) ), this, SLOT( onIndexActivated( QModelIndex ) ) ); - connect( playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), this, SLOT( onTrackCountChanged( unsigned int ) ) ); + connect( parent, SIGNAL( itemActivated( QModelIndex ) ), SLOT( onIndexActivated( QModelIndex ) ) ); + connect( playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); + connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ) ); } @@ -42,6 +43,19 @@ QueueProxyModel::~QueueProxyModel() } +void +QueueProxyModel::onPlaybackStarted( const Tomahawk::result_ptr& result ) +{ + for ( int i = 0; i < rowCount(); i++ ) + { + QModelIndex idx = index( i, 0 ); + PlayableItem* item = itemFromIndex( mapToSource( idx ) ); + if ( item && item->query() && item->query()->equals( result->toQuery() ) ) + remove( idx ); + } +} + + void QueueProxyModel::onIndexActivated( const QModelIndex& index ) { diff --git a/src/libtomahawk/playlist/QueueProxyModel.h b/src/libtomahawk/playlist/QueueProxyModel.h index 3ea2f9254..3c39a68dc 100644 --- a/src/libtomahawk/playlist/QueueProxyModel.h +++ b/src/libtomahawk/playlist/QueueProxyModel.h @@ -38,6 +38,7 @@ public: private slots: void onIndexActivated( const QModelIndex& index ); void onTrackCountChanged( unsigned int count ); + void onPlaybackStarted( const Tomahawk::result_ptr& result ); }; #endif // QUEUEPROXYMODEL_H From 8841fa48bf386d7f917207ed43598e95d9709bda Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 01:58:41 +0200 Subject: [PATCH 207/433] * QueueModel is now created by the QueueView directly. --- src/TomahawkWindow.cpp | 4 ---- src/TomahawkWindow.h | 1 - 2 files changed, 5 deletions(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 3f30045c6..92a2b59f2 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -260,10 +260,6 @@ TomahawkWindow::setupSideBar() jobsView->setModel( m_jobsModel ); m_queueView = new QueueView( m_sidebar ); - m_queueModel = new PlaylistModel( m_queueView ); - m_queueModel->setStyle( PlaylistModel::Short ); - m_queueView->queue()->setPlaylistModel( m_queueModel ); - m_queueView->queue()->playlistModel()->setReadOnly( false ); AudioEngine::instance()->setQueue( m_queueView->queue()->proxyModel()->playlistInterface() ); m_sidebar->addWidget( m_sourcetree ); diff --git a/src/TomahawkWindow.h b/src/TomahawkWindow.h index f84965e20..dee2122ff 100644 --- a/src/TomahawkWindow.h +++ b/src/TomahawkWindow.h @@ -148,7 +148,6 @@ private: SourceTreeView* m_sourcetree; QPushButton* m_statusButton; QPushButton* m_queueButton; - PlaylistModel* m_queueModel; QueueView* m_queueView; AnimatedSplitter* m_sidebar; JobStatusModel* m_jobsModel; From c3570e8e53eeb470b403c2ef2181836f78ebdfdb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 02:01:53 +0200 Subject: [PATCH 208/433] * Added comment to tr(). --- src/sourcetree/SourceTreeView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index c45a66d87..fb2dfbd7b 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -358,7 +358,8 @@ SourceTreeView::deletePlaylist( const QModelIndex& idxIn ) } QMessageBox askDelete( QMessageBox::Question, tr( "Delete %1?", "playlist/station/..." ).arg( typeDesc ), - tr( "Would you like to delete the %1 \"%2\"?" ).arg( typeDesc ).arg( idx.data().toString() ), + tr( "Would you like to delete the %1 \"%2\"?", "e.g. Would you like to delete the playlist named Foobar?" ) + .arg( typeDesc ).arg( idx.data().toString() ), QMessageBox::Yes | QMessageBox::No, this ); int r = askDelete.exec(); From 497c0f01c234bb951475d6e861dd1519db0d1f76 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 02:16:56 +0200 Subject: [PATCH 209/433] * Call insert instead of insertInternal so it gets called correctly, in case it's overwritten. --- src/libtomahawk/playlist/PlayableModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index 3581ae92d..d2b7e3f97 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -586,7 +586,7 @@ PlayableModel::insertInternal( const T& item, int row ) QList< T > list; list << item; - insertInternal( list, row ); + insert( list, row ); } From b62b9c35319f62604468fcfa63dbf2b3815f09b9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 02:17:08 +0200 Subject: [PATCH 210/433] * Style fix for DynamicView. --- src/libtomahawk/playlist/dynamic/DynamicView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/DynamicView.cpp b/src/libtomahawk/playlist/dynamic/DynamicView.cpp index 47ebc8d3c..06d858f11 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicView.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicView.cpp @@ -71,13 +71,13 @@ DynamicView::~DynamicView() void -DynamicView::setDynamicModel( DynamicModel* model) +DynamicView::setDynamicModel( DynamicModel* model ) { m_model = model; PlaylistView::setPlaylistModel( m_model ); connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); - connect( m_model, SIGNAL( checkForOverflow() ), this, SLOT( checkForOverflow() ) ); + connect( m_model, SIGNAL( checkForOverflow() ), SLOT( checkForOverflow() ) ); } From 65710f9d515de0fb0db4f12e1f5f3c553bc2be2f Mon Sep 17 00:00:00 2001 From: Ahmed Date: Fri, 25 May 2012 21:29:45 +0200 Subject: [PATCH 211/433] Changes to the DiagnosticsDialog that updates when any changes happens --- src/DiagnosticsDialog.cpp | 160 +++++++++++++++++++++++++++++++++++--- src/DiagnosticsDialog.h | 19 +++++ src/DiagnosticsDialog.ui | 16 +++- 3 files changed, 182 insertions(+), 13 deletions(-) diff --git a/src/DiagnosticsDialog.cpp b/src/DiagnosticsDialog.cpp index 35ff7e9dc..08376388b 100644 --- a/src/DiagnosticsDialog.cpp +++ b/src/DiagnosticsDialog.cpp @@ -26,11 +26,13 @@ #include "network/Servent.h" #include "SourceList.h" +#include #include #include #include #include #include +#include #include "utils/Logger.h" #include "sip/SipHandler.h" @@ -42,10 +44,12 @@ DiagnosticsDialog::DiagnosticsDialog( QWidget *parent ) { ui->setupUi( this ); - connect( ui->updateButton, SIGNAL( clicked() ), this, SLOT( updateLogView() ) ); + //connect( ui->updateButton, SIGNAL( clicked() ), this, SLOT( updateLogView() ) ); connect( ui->clipboardButton, SIGNAL( clicked() ), this, SLOT( copyToClipboard() ) ); connect( ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); + ui->scrollAreaWidgetContents->setLayout( new QVBoxLayout() ); + updateLogView(); } @@ -60,7 +64,7 @@ void DiagnosticsDialog::updateLogView() // network log.append( - "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n\n" + "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n" ); // network @@ -89,11 +93,15 @@ void DiagnosticsDialog::updateLogView() ) ); } - log.append("\n\n"); - + //log.append("\n\n"); + ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( log, this ) ); + // Peers / Accounts, TODO - log.append("ACCOUNTS:\n"); + ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( "ACCOUNTS:\n", this ) ); + + QString accountInfo; + const QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true ); const QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType ); foreach ( Tomahawk::Accounts::Account* account, accounts ) @@ -102,6 +110,13 @@ void DiagnosticsDialog::updateLogView() if ( !account || !account->sipPlugin() ) continue; + connect( account, SIGNAL(connectionStateChanged(Tomahawk::Accounts::Account::ConnectionState)), SLOT(onAccountConnectionStateChanged(Tomahawk::Accounts::Account::ConnectionState)) ); + connect( account, SIGNAL(error(int,QString)), SLOT(onAccountError(int,QString)) ); + connect( account->sipPlugin(), SIGNAL(peerOnline(QString)), SLOT(onPeerOnline(QString)) ); + connect( account->sipPlugin(), SIGNAL(peerOffline(QString)), SLOT(onPeerOffline(QString)) ); + connect( account->sipPlugin(), SIGNAL(sipInfoReceived(QString,SipInfo)), SLOT(onSipInfoReceived(QString,SipInfo)) ); + connect( account->sipPlugin(), SIGNAL(softwareVersionReceived(QString,QString)), SLOT(onSoftwareVersionReceived(QString,QString)) ); + QString stateString; switch( account->connectionState() ) { @@ -118,7 +133,7 @@ void DiagnosticsDialog::updateLogView() case Tomahawk::Accounts::Account::Disconnecting: stateString = "Disconnecting"; } - log.append( + accountInfo.append( QString( " %2 (%1): %3 (%4)\n" ) .arg( account->accountServiceName() ) .arg( account->sipPlugin()->friendlyName() ) @@ -142,7 +157,7 @@ void DiagnosticsDialog::updateLogView() QString versionString = SipHandler::instance()->versionString( peerId ); SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId ); if( !sipInfo.isValid() ) - log.append( + accountInfo.append( QString(" %1: %2 %3" /*"(%4)"*/ "\n") .arg( peerId ) .arg( "sipinfo invalid" ) @@ -150,7 +165,7 @@ void DiagnosticsDialog::updateLogView() // .arg( connected ? "connected" : "not connected") ); else if( sipInfo.isVisible() ) - log.append( + accountInfo.append( QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n") .arg( peerId ) .arg( sipInfo.host().hostName() ) @@ -160,7 +175,7 @@ void DiagnosticsDialog::updateLogView() ); else - log.append( + accountInfo.append( QString(" %1: visible: false %2" /*" (%3)"*/ "\n") .arg( peerId ) .arg( versionString ) @@ -168,13 +183,134 @@ void DiagnosticsDialog::updateLogView() ); } - log.append("\n"); + accountInfo.append("\n"); + + QLabel *accountInfoLabel = new QLabel( accountInfo, this ); + + ui->scrollAreaWidgetContents->layout()->addWidget( accountInfoLabel ); + + m_accountDescriptionStore.insert( account, accountInfoLabel ); + + accountInfo.clear(); } - ui->logView->setPlainText(log); + //ui->logView->setPlainText(log); } void DiagnosticsDialog::copyToClipboard() { - QApplication::clipboard()->setText( ui->logView->toPlainText() ); + //QApplication::clipboard()->setText( ui->logView->toPlainText() ); } +void DiagnosticsDialog::onAccountConnectionStateChanged(Tomahawk::Accounts::Account::ConnectionState state) +{ + Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() ); + Q_ASSERT( account ); + + updateAccountLabel( account ); +} + +void DiagnosticsDialog::onAccountError(int errorId, QString errorString) +{ + Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() ); + Q_ASSERT( account ); +} + +void DiagnosticsDialog::onPeerOnline(const QString& ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT(account); + + updateAccountLabel( account ); +} + +void DiagnosticsDialog::onPeerOffline(const QString& ) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT(account); + + updateAccountLabel( account ); +} + +void DiagnosticsDialog::onSipInfoReceived(const QString& peerId, const SipInfo& info) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT(account); + + updateAccountLabel( account ); +} + +void DiagnosticsDialog::onSoftwareVersionReceived(const QString& peerId, const QString& versionString) +{ + Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); + Q_ASSERT(account); + + updateAccountLabel( account ); +} + +void DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account) +{ + QLabel* accountInfoLabel = m_accountDescriptionStore.value(account); + + if( accountInfoLabel ) + { + QString accountInfo; + QString stateString; + switch( account->connectionState() ) + { + case Tomahawk::Accounts::Account::Connecting: + stateString = "Connecting"; + break; + case Tomahawk::Accounts::Account::Connected: + stateString = "Connected"; + break; + + case Tomahawk::Accounts::Account::Disconnected: + stateString = "Disconnected"; + break; + case Tomahawk::Accounts::Account::Disconnecting: + stateString = "Disconnecting"; + } + accountInfo.append( + QString( " %2 (%1): %3 (%4)\n" ) + .arg( account->accountServiceName() ) + .arg( account->sipPlugin()->friendlyName() ) + .arg( account->accountFriendlyName()) + .arg( stateString ) + ); + + foreach( const QString &peerId, account->sipPlugin()->peersOnline() ) + { + QString versionString = SipHandler::instance()->versionString( peerId ); + SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId ); + if( !sipInfo.isValid() ) + accountInfo.append( + QString(" %1: %2 %3" /*"(%4)"*/ "\n") + .arg( peerId ) + .arg( "sipinfo invalid" ) + .arg( versionString ) + // .arg( connected ? "connected" : "not connected") + ); + else if( sipInfo.isVisible() ) + accountInfo.append( + QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n") + .arg( peerId ) + .arg( sipInfo.host().hostName() ) + .arg( sipInfo.port() ) + .arg( versionString ) + // .arg( connected ? "connected" : "not connected") + + ); + else + accountInfo.append( + QString(" %1: visible: false %2" /*" (%3)"*/ "\n") + .arg( peerId ) + .arg( versionString ) + // .arg( connected ? "connected" : "not connected") + + ); + } + accountInfo.append("\n"); + + accountInfoLabel->setText( accountInfo ); + } +} \ No newline at end of file diff --git a/src/DiagnosticsDialog.h b/src/DiagnosticsDialog.h index e3fed2b59..99da5aae9 100644 --- a/src/DiagnosticsDialog.h +++ b/src/DiagnosticsDialog.h @@ -19,7 +19,15 @@ #ifndef DIGANOSTICSDIALOG_H #define DIAGNOSTICSDIALOG_H +#include "accounts/Account.h" + #include +#include + + +class QLabel; + +class SipInfo; namespace Ui { @@ -37,8 +45,19 @@ public: private slots: void updateLogView(); void copyToClipboard(); + + void onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState state ); + void onAccountError( int errorId, QString errorString ); + void onPeerOnline( const QString& ); + void onPeerOffline( const QString& ); + void onSipInfoReceived( const QString& peerId, const SipInfo& info ); + void onSoftwareVersionReceived( const QString& peerId, const QString& versionString ); + void updateAccountLabel( Tomahawk::Accounts::Account* ); private: + + QMap< Tomahawk::Accounts::Account*, QLabel* > m_accountDescriptionStore; + Ui::DiagnosticsDialog* ui; }; diff --git a/src/DiagnosticsDialog.ui b/src/DiagnosticsDialog.ui index 6d884eba6..e27b4b25e 100644 --- a/src/DiagnosticsDialog.ui +++ b/src/DiagnosticsDialog.ui @@ -26,7 +26,21 @@ - + + + true + + + + + 0 + 0 + 708 + 386 + + + + From 062e7a5a3e588bf08ad8118b12522969f61c6646 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 03:05:20 +0200 Subject: [PATCH 212/433] * Cleanup DiagnosticsDialog. Remove update button and fix copying to clipboard. --- src/DiagnosticsDialog.cpp | 184 ++++++++++++++------------------------ src/DiagnosticsDialog.ui | 7 -- 2 files changed, 65 insertions(+), 126 deletions(-) diff --git a/src/DiagnosticsDialog.cpp b/src/DiagnosticsDialog.cpp index 08376388b..e63a6fe16 100644 --- a/src/DiagnosticsDialog.cpp +++ b/src/DiagnosticsDialog.cpp @@ -44,7 +44,6 @@ DiagnosticsDialog::DiagnosticsDialog( QWidget *parent ) { ui->setupUi( this ); - //connect( ui->updateButton, SIGNAL( clicked() ), this, SLOT( updateLogView() ) ); connect( ui->clipboardButton, SIGNAL( clicked() ), this, SLOT( copyToClipboard() ) ); connect( ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); @@ -53,7 +52,9 @@ DiagnosticsDialog::DiagnosticsDialog( QWidget *parent ) updateLogView(); } -void DiagnosticsDialog::updateLogView() + +void +DiagnosticsDialog::updateLogView() { QString log; @@ -63,16 +64,11 @@ void DiagnosticsDialog::updateLogView() ); // network - log.append( - "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n" - ); + log.append( "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n" ); // network - log.append( - "NETWORK:\n" - " General:\n" - ); - if( Servent::instance()->visibleExternally() ) + log.append( "NETWORK:\n General:\n" ); + if ( Servent::instance()->visibleExternally() ) { log.append( QString( @@ -87,21 +83,13 @@ void DiagnosticsDialog::updateLogView() } else { - log.append( - QString( - " visible: false" - ) - ); + log.append( " visible: false" ); } - //log.append("\n\n"); ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( log, this ) ); - // Peers / Accounts, TODO ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( "ACCOUNTS:\n", this ) ); - QString accountInfo; - const QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true ); const QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType ); foreach ( Tomahawk::Accounts::Account* account, accounts ) @@ -110,98 +98,40 @@ void DiagnosticsDialog::updateLogView() if ( !account || !account->sipPlugin() ) continue; - connect( account, SIGNAL(connectionStateChanged(Tomahawk::Accounts::Account::ConnectionState)), SLOT(onAccountConnectionStateChanged(Tomahawk::Accounts::Account::ConnectionState)) ); - connect( account, SIGNAL(error(int,QString)), SLOT(onAccountError(int,QString)) ); - connect( account->sipPlugin(), SIGNAL(peerOnline(QString)), SLOT(onPeerOnline(QString)) ); - connect( account->sipPlugin(), SIGNAL(peerOffline(QString)), SLOT(onPeerOffline(QString)) ); - connect( account->sipPlugin(), SIGNAL(sipInfoReceived(QString,SipInfo)), SLOT(onSipInfoReceived(QString,SipInfo)) ); - connect( account->sipPlugin(), SIGNAL(softwareVersionReceived(QString,QString)), SLOT(onSoftwareVersionReceived(QString,QString)) ); - - QString stateString; - switch( account->connectionState() ) - { - case Tomahawk::Accounts::Account::Connecting: - stateString = "Connecting"; - break; - case Tomahawk::Accounts::Account::Connected: - stateString = "Connected"; - break; - - case Tomahawk::Accounts::Account::Disconnected: - stateString = "Disconnected"; - break; - case Tomahawk::Accounts::Account::Disconnecting: - stateString = "Disconnecting"; - } - accountInfo.append( - QString( " %2 (%1): %3 (%4)\n" ) - .arg( account->accountServiceName() ) - .arg( account->sipPlugin()->friendlyName() ) - .arg( account->accountFriendlyName()) - .arg( stateString ) - ); - - foreach( const QString &peerId, account->sipPlugin()->peersOnline() ) - { - /* enable this again, when we check the Source.has this peerId - bool connected = false; - Q_FOREACH( const Tomahawk::source_ptr &source, sources ) - { - if( source->controlConnection() ) - { - connected = true; - break; - } - }*/ - - QString versionString = SipHandler::instance()->versionString( peerId ); - SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId ); - if( !sipInfo.isValid() ) - accountInfo.append( - QString(" %1: %2 %3" /*"(%4)"*/ "\n") - .arg( peerId ) - .arg( "sipinfo invalid" ) - .arg( versionString ) - // .arg( connected ? "connected" : "not connected") - ); - else if( sipInfo.isVisible() ) - accountInfo.append( - QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n") - .arg( peerId ) - .arg( sipInfo.host().hostName() ) - .arg( sipInfo.port() ) - .arg( versionString ) - // .arg( connected ? "connected" : "not connected") - - ); - else - accountInfo.append( - QString(" %1: visible: false %2" /*" (%3)"*/ "\n") - .arg( peerId ) - .arg( versionString ) - // .arg( connected ? "connected" : "not connected") - - ); - } - accountInfo.append("\n"); - - QLabel *accountInfoLabel = new QLabel( accountInfo, this ); + connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), + SLOT( onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) ); + connect( account, SIGNAL( error( int, QString ) ), + SLOT( onAccountError( int, QString ) ) ); + + connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) ); + connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) ); + connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( onSipInfoReceived( QString, SipInfo ) ) ); + connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( onSoftwareVersionReceived( QString, QString ) ) ); + QLabel* accountInfoLabel = new QLabel( this ); ui->scrollAreaWidgetContents->layout()->addWidget( accountInfoLabel ); - m_accountDescriptionStore.insert( account, accountInfoLabel ); - accountInfo.clear(); + updateAccountLabel( account ); } - //ui->logView->setPlainText(log); } -void DiagnosticsDialog::copyToClipboard() + +void +DiagnosticsDialog::copyToClipboard() { - //QApplication::clipboard()->setText( ui->logView->toPlainText() ); + QString log; + foreach ( QLabel* label, m_accountDescriptionStore.values() ) + { + log += label->text() + "\n\n"; + } + + QApplication::clipboard()->setText( log ); } -void DiagnosticsDialog::onAccountConnectionStateChanged(Tomahawk::Accounts::Account::ConnectionState state) + +void +DiagnosticsDialog::onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState /* state */ ) { Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() ); Q_ASSERT( account ); @@ -209,49 +139,61 @@ void DiagnosticsDialog::onAccountConnectionStateChanged(Tomahawk::Accounts::Acco updateAccountLabel( account ); } -void DiagnosticsDialog::onAccountError(int errorId, QString errorString) + +void +DiagnosticsDialog::onAccountError( int /* errorId */ , QString /* errorString */ ) { Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() ); Q_ASSERT( account ); } -void DiagnosticsDialog::onPeerOnline(const QString& ) + +void +DiagnosticsDialog::onPeerOnline( const QString& ) { Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); - Q_ASSERT(account); + Q_ASSERT( account ); updateAccountLabel( account ); } -void DiagnosticsDialog::onPeerOffline(const QString& ) + +void +DiagnosticsDialog::onPeerOffline( const QString& ) { Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); - Q_ASSERT(account); + Q_ASSERT( account ); updateAccountLabel( account ); } -void DiagnosticsDialog::onSipInfoReceived(const QString& peerId, const SipInfo& info) + +void +DiagnosticsDialog::onSipInfoReceived( const QString& /* peerId */ , const SipInfo& /* info */ ) { Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); - Q_ASSERT(account); + Q_ASSERT( account ); updateAccountLabel( account ); } -void DiagnosticsDialog::onSoftwareVersionReceived(const QString& peerId, const QString& versionString) + +void +DiagnosticsDialog::onSoftwareVersionReceived( const QString& /* peerId */ , const QString& /* versionString */ ) { Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account(); - Q_ASSERT(account); + Q_ASSERT( account ); updateAccountLabel( account ); } -void DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account) + +void +DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account ) { - QLabel* accountInfoLabel = m_accountDescriptionStore.value(account); + QLabel* accountInfoLabel = m_accountDescriptionStore.value( account ); - if( accountInfoLabel ) + if ( accountInfoLabel ) { QString accountInfo; QString stateString; @@ -278,11 +220,12 @@ void DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account .arg( stateString ) ); - foreach( const QString &peerId, account->sipPlugin()->peersOnline() ) + foreach( const QString& peerId, account->sipPlugin()->peersOnline() ) { QString versionString = SipHandler::instance()->versionString( peerId ); SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId ); - if( !sipInfo.isValid() ) + if ( !sipInfo.isValid() ) + { accountInfo.append( QString(" %1: %2 %3" /*"(%4)"*/ "\n") .arg( peerId ) @@ -290,7 +233,9 @@ void DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account .arg( versionString ) // .arg( connected ? "connected" : "not connected") ); - else if( sipInfo.isVisible() ) + } + else if ( sipInfo.isVisible() ) + { accountInfo.append( QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n") .arg( peerId ) @@ -298,18 +243,19 @@ void DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account .arg( sipInfo.port() ) .arg( versionString ) // .arg( connected ? "connected" : "not connected") - ); + } else + { accountInfo.append( QString(" %1: visible: false %2" /*" (%3)"*/ "\n") .arg( peerId ) .arg( versionString ) // .arg( connected ? "connected" : "not connected") - ); + } } - accountInfo.append("\n"); + accountInfo.append( "\n" ); accountInfoLabel->setText( accountInfo ); } diff --git a/src/DiagnosticsDialog.ui b/src/DiagnosticsDialog.ui index e27b4b25e..d304b65f6 100644 --- a/src/DiagnosticsDialog.ui +++ b/src/DiagnosticsDialog.ui @@ -46,13 +46,6 @@ - - - - Update - - - From 690c80db60e4577e19abc2ddfb1c35ef3c6fd497 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 03:34:17 +0200 Subject: [PATCH 213/433] * DRY: Call main window and let it create a new playlist. --- src/sourcetree/items/CategoryItems.cpp | 50 +++++++------------------- src/sourcetree/items/CategoryItems.h | 2 +- 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/src/sourcetree/items/CategoryItems.cpp b/src/sourcetree/items/CategoryItems.cpp index 9ea1e005b..7ef745226 100644 --- a/src/sourcetree/items/CategoryItems.cpp +++ b/src/sourcetree/items/CategoryItems.cpp @@ -29,7 +29,6 @@ #include "utils/TomahawkUtils.h" #include "widgets/NewPlaylistWidget.h" #include "TomahawkWindow.h" -#include "widgets/PlaylistTypeSelectorDialog.h" #include #include "utils/Logger.h" #include "DropJob.h" @@ -57,11 +56,13 @@ CategoryAddItem::~CategoryAddItem() QString CategoryAddItem::text() const { - switch( m_categoryType ) { + switch( m_categoryType ) + { case SourcesModel::PlaylistsCategory: - return tr( "New Playlist" ); + return tr( "Create new Playlist" ); + case SourcesModel::StationsCategory: - return tr( "New Station" ); + return tr( "Create new Station" ); } return QString(); @@ -73,46 +74,16 @@ CategoryAddItem::activate() { switch( m_categoryType ) { - case SourcesModel::PlaylistsCategory: { - - PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet ); -#ifndef Q_WS_MAC - playlistSelectorDlg->setModal( true ); -#endif - connect( playlistSelectorDlg, SIGNAL( finished( int ) ), this, SLOT( dialogClosed( int ) ) ); - - playlistSelectorDlg->show(); + case SourcesModel::PlaylistsCategory: + APP->mainWindow()->createPlaylist(); break; - } + case SourcesModel::StationsCategory: APP->mainWindow()->createStation(); break; } } -void -CategoryAddItem::dialogClosed( int ret ) -{ - PlaylistTypeSelectorDlg* playlistSelectorDlg = qobject_cast< PlaylistTypeSelectorDlg* >( sender() ); - Q_ASSERT( playlistSelectorDlg ); - - QString playlistName = playlistSelectorDlg->playlistName(); - if ( playlistName.isEmpty() ) - playlistName = tr( "New Playlist" ); - - if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) { - - playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() ); - ViewManager::instance()->show( playlist ); - - } else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) { - // create Auto Playlist - APP->mainWindow()->createAutomaticPlaylist( playlistName ); - } else if ( !ret ) { - model()->viewPageActivated( ViewManager::instance()->currentPage() ); - } - playlistSelectorDlg->deleteLater(); -} Qt::ItemFlags CategoryAddItem::flags() const @@ -121,8 +92,10 @@ CategoryAddItem::flags() const { case SourcesModel::PlaylistsCategory: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; + case SourcesModel::StationsCategory: return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; + default: return Qt::ItemIsEnabled; break; @@ -144,9 +117,11 @@ CategoryAddItem::willAcceptDrag( const QMimeData* data ) const { return true; } + return false; } + SourceTreeItem::DropTypes CategoryAddItem::supportedDropTypes( const QMimeData* data ) const { @@ -284,6 +259,7 @@ CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction ) return true; } + void CategoryAddItem::playlistToRenameLoaded() { diff --git a/src/sourcetree/items/CategoryItems.h b/src/sourcetree/items/CategoryItems.h index 6c03d6d5f..85db4578f 100644 --- a/src/sourcetree/items/CategoryItems.h +++ b/src/sourcetree/items/CategoryItems.h @@ -40,10 +40,10 @@ public: private slots: void parsedDroppedTracks( const QList< Tomahawk::query_ptr >& tracks ); - void dialogClosed( int ret ); // Do the rename only after the revision is loaded void playlistToRenameLoaded(); + private: SourcesModel::CategoryType m_categoryType; QIcon m_icon; From faf8cf1539fcdb52e28f6ab4648d94124313f387 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 03:34:57 +0200 Subject: [PATCH 214/433] * Fixed TWK-839: Creating name-less playlists results in a better default name. --- src/TomahawkWindow.cpp | 66 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 92a2b59f2..1a7734404 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -698,18 +698,18 @@ TomahawkWindow::onAudioEngineError( AudioEngine::AudioErrorCode /* error */ ) void TomahawkWindow::createAutomaticPlaylist( QString playlistName ) { - QString name = playlistName; - - if ( name.isEmpty() ) + if ( playlistName.isEmpty() ) return; source_ptr author = SourceList::instance()->getLocal(); QString id = uuid(); QString info = ""; // FIXME QString creator = "someone"; // FIXME - dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, name, info, creator, Static, false ); + + dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, Static, false ); playlist->setMode( Static ); playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls(), playlist->entries() ); + ViewManager::instance()->show( playlist ); } @@ -717,18 +717,36 @@ TomahawkWindow::createAutomaticPlaylist( QString playlistName ) void TomahawkWindow::createStation() { + QString title = tr( "Station" ); bool ok; - QString name = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, tr( "New Station" ), &ok ); - if ( !ok || name.isEmpty() ) + QString playlistName = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, title, &ok ); + if ( !ok ) return; + if ( playlistName.isEmpty() || playlistName == title ) + { + QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->stations(); + QStringList titles; + foreach ( const playlist_ptr& pl, pls ) + titles << pl->title(); + + playlistName = title; + int i = 2; + while ( titles.contains( playlistName ) ) + { + playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ ); + } + } + source_ptr author = SourceList::instance()->getLocal(); QString id = uuid(); QString info = ""; // FIXME QString creator = "someone"; // FIXME - dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, name, info, creator, OnDemand, false ); + + dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, OnDemand, false ); playlist->setMode( OnDemand ); playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls() ); + ViewManager::instance()->show( playlist ); } @@ -754,17 +772,47 @@ TomahawkWindow::playlistCreateDialogFinished( int ret ) Q_ASSERT( playlistSelectorDlg ); QString playlistName = playlistSelectorDlg->playlistName(); - if ( playlistName.isEmpty() ) - playlistName = tr( "New Playlist" ); if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret ) { + if ( playlistName.isEmpty() ) + { + QList< playlist_ptr > pls = SourceList::instance()->getLocal()->collection()->playlists(); + QStringList titles; + foreach ( const playlist_ptr& pl, pls ) + titles << pl->title(); + + QString title = tr( "Playlist" ); + playlistName = title; + int i = 2; + while ( titles.contains( playlistName ) ) + { + playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ ); + } + } + playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() ); ViewManager::instance()->show( playlist ); } else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret ) { // create Auto Playlist + if ( playlistName.isEmpty() ) + { + QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->autoPlaylists(); + QStringList titles; + foreach ( const dynplaylist_ptr& pl, pls ) + titles << pl->title(); + + QString title = tr( "Automatic Playlist" ); + playlistName = title; + int i = 2; + while ( titles.contains( playlistName ) ) + { + playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ ); + } + } + createAutomaticPlaylist( playlistName ); } From f5bdc3a30b24ded2f877e0c8bc4d0be0d3c82159 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:23:03 +0200 Subject: [PATCH 215/433] * Got rid of obsolete CollectionProxyModel*. --- src/libtomahawk/CMakeLists.txt | 2 - .../playlist/CollectionProxyModel.cpp | 46 ------------------- .../playlist/CollectionProxyModel.h | 40 ---------------- .../CollectionProxyModelPlaylistInterface.cpp | 38 --------------- .../CollectionProxyModelPlaylistInterface.h | 46 ------------------- src/libtomahawk/playlist/CollectionView.cpp | 3 +- 6 files changed, 1 insertion(+), 174 deletions(-) delete mode 100644 src/libtomahawk/playlist/CollectionProxyModel.cpp delete mode 100644 src/libtomahawk/playlist/CollectionProxyModel.h delete mode 100644 src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp delete mode 100644 src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 60cfd43c9..ee0f0e27d 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -50,8 +50,6 @@ set( libGuiSources playlist/TreeProxyModelPlaylistInterface.cpp playlist/TreeHeader.cpp playlist/TreeItemDelegate.cpp - playlist/CollectionProxyModel.cpp - playlist/CollectionProxyModelPlaylistInterface.cpp playlist/CollectionView.cpp playlist/PlaylistModel.cpp playlist/PlaylistView.cpp diff --git a/src/libtomahawk/playlist/CollectionProxyModel.cpp b/src/libtomahawk/playlist/CollectionProxyModel.cpp deleted file mode 100644 index 960409717..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModel.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionProxyModel.h" - -#include "CollectionProxyModelPlaylistInterface.h" - -#include - -#include "Album.h" -#include "Query.h" -#include "utils/Logger.h" -#include "Source.h" - - -CollectionProxyModel::CollectionProxyModel( QObject* parent ) - : PlayableProxyModel( parent ) -{ -} - -Tomahawk::playlistinterface_ptr -CollectionProxyModel::playlistInterface() -{ - if ( m_playlistInterface.isNull() ) - { - m_playlistInterface = Tomahawk::playlistinterface_ptr( new Tomahawk::CollectionProxyModelPlaylistInterface( this ) ); - } - - return m_playlistInterface; -} diff --git a/src/libtomahawk/playlist/CollectionProxyModel.h b/src/libtomahawk/playlist/CollectionProxyModel.h deleted file mode 100644 index 17ae207b2..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModel.h +++ /dev/null @@ -1,40 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONPROXYMODEL_H -#define COLLECTIONPROXYMODEL_H - -#include "PlayableProxyModel.h" -#include "PlayableProxyModelPlaylistInterface.h" - -#include "DllMacro.h" - -class DLLEXPORT CollectionProxyModel : public PlayableProxyModel -{ -Q_OBJECT - -public: - explicit CollectionProxyModel( QObject* parent = 0 ); - virtual ~CollectionProxyModel() {} - - virtual Tomahawk::playlistinterface_ptr playlistInterface(); - -}; - -#endif // COLLECTIONPROXYMODEL_H diff --git a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp b/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp deleted file mode 100644 index b3144c343..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionProxyModelPlaylistInterface.h" - -#include "CollectionProxyModel.h" -#include "Album.h" -#include "Query.h" -#include "Source.h" -#include "utils/Logger.h" - -using namespace Tomahawk; - -CollectionProxyModelPlaylistInterface::CollectionProxyModelPlaylistInterface( CollectionProxyModel *proxyModel ) - : PlayableProxyModelPlaylistInterface( proxyModel ) -{ -} - -CollectionProxyModelPlaylistInterface::~CollectionProxyModelPlaylistInterface() -{ - m_proxyModel.clear(); -} diff --git a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h b/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h deleted file mode 100644 index 386cd25ee..000000000 --- a/src/libtomahawk/playlist/CollectionProxyModelPlaylistInterface.h +++ /dev/null @@ -1,46 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONPROXYMODELPLAYLISTINTERFACE_H -#define COLLECTIONPROXYMODELPLAYLISTINTERFACE_H - -#include "PlayableProxyModel.h" -#include "PlayableProxyModelPlaylistInterface.h" - -#include "DllMacro.h" - -class CollectionProxyModel; - -namespace Tomahawk -{ - -class DLLEXPORT CollectionProxyModelPlaylistInterface : public PlayableProxyModelPlaylistInterface -{ -Q_OBJECT - -public: - explicit CollectionProxyModelPlaylistInterface( CollectionProxyModel* proxyModel ); - virtual ~CollectionProxyModelPlaylistInterface(); - - virtual PlaylistModes::ViewMode viewMode() const { return PlaylistModes::Flat; } -}; - -} //ns - -#endif // COLLECTIONPROXYMODELPLAYLISTINTERFACE_H diff --git a/src/libtomahawk/playlist/CollectionView.cpp b/src/libtomahawk/playlist/CollectionView.cpp index 0054c16e7..5733f4d8f 100644 --- a/src/libtomahawk/playlist/CollectionView.cpp +++ b/src/libtomahawk/playlist/CollectionView.cpp @@ -22,7 +22,6 @@ #include #include -#include "CollectionProxyModel.h" #include "PlayableModel.h" #include "widgets/OverlayWidget.h" #include "utils/Logger.h" @@ -34,7 +33,7 @@ using namespace Tomahawk; CollectionView::CollectionView( QWidget* parent ) : TrackView( parent ) { - setProxyModel( new CollectionProxyModel( this ) ); + setProxyModel( new PlayableProxyModel( this ) ); setDragDropMode( QAbstractItemView::DragOnly ); } From fad3c6d12a677317a15e143b01cfe65312efd7fa Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:46:02 +0200 Subject: [PATCH 216/433] * TrackView now has a default ViewPage implementation and inheritance. --- src/libtomahawk/playlist/TrackView.cpp | 38 ++++++++++++++++++++++++++ src/libtomahawk/playlist/TrackView.h | 15 +++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index 3b55f288e..9a5d0e827 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -99,6 +99,8 @@ TrackView::TrackView( QWidget* parent ) connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) ); connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); + + setProxyModel( new PlayableProxyModel( this ) ); } @@ -701,3 +703,39 @@ TrackView::mousePressEvent( QMouseEvent* event ) } } } + + +Tomahawk::playlistinterface_ptr +TrackView::playlistInterface() const +{ + return proxyModel()->playlistInterface(); +} + + +QString +TrackView::title() const +{ + return model()->title(); +} + + +QString +TrackView::description() const +{ + return model()->description(); +} + + +QPixmap +TrackView::pixmap() const +{ + return QPixmap( RESPATH "images/music-icon.png" ); +} + + +bool +TrackView::jumpToCurrentTrack() +{ + scrollTo( proxyModel()->currentIndex(), QAbstractItemView::PositionAtCenter ); + return true; +} diff --git a/src/libtomahawk/playlist/TrackView.h b/src/libtomahawk/playlist/TrackView.h index 634139f3a..eb6583b22 100644 --- a/src/libtomahawk/playlist/TrackView.h +++ b/src/libtomahawk/playlist/TrackView.h @@ -26,6 +26,7 @@ #include "ContextMenu.h" #include "PlaylistItemDelegate.h" +#include "ViewPage.h" #include "DllMacro.h" @@ -36,7 +37,7 @@ class PlayableModel; class PlayableProxyModel; class OverlayWidget; -class DLLEXPORT TrackView : public QTreeView +class DLLEXPORT TrackView : public QTreeView, public Tomahawk::ViewPage { Q_OBJECT @@ -59,6 +60,18 @@ public: Tomahawk::ContextMenu* contextMenu() const { return m_contextMenu; } AnimatedSpinner* loadingSpinner() const { return m_loadingSpinner; } + virtual QWidget* widget() { return this; } + virtual Tomahawk::playlistinterface_ptr playlistInterface() const; + + virtual QString title() const; + virtual QString description() const; + virtual QPixmap pixmap() const; + + virtual bool showModes() const { return true; } + virtual bool showFilter() const { return true; } + + virtual bool jumpToCurrentTrack(); + QModelIndex hoveredIndex() const { return m_hoveredIndex; } QModelIndex contextMenuIndex() const { return m_contextMenuIndex; } void setContextMenuIndex( const QModelIndex& idx ) { m_contextMenuIndex = idx; } From 175b413584fab5996669eae2347b87404e228a43 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:46:48 +0200 Subject: [PATCH 217/433] * TrackView's default ViewPage implementation is good enough for PlaylistView. --- src/libtomahawk/playlist/PlaylistView.cpp | 11 ----------- src/libtomahawk/playlist/PlaylistView.h | 10 +--------- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index d42d1dfe2..e6a2e4675 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -35,8 +35,6 @@ PlaylistView::PlaylistView( QWidget* parent ) : TrackView( parent ) , m_model( 0 ) { - setProxyModel( new PlayableProxyModel( this ) ); - connect( contextMenu(), SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); } @@ -132,14 +130,6 @@ PlaylistView::onTrackCountChanged( unsigned int tracks ) } -bool -PlaylistView::jumpToCurrentTrack() -{ - scrollTo( proxyModel()->currentIndex(), QAbstractItemView::PositionAtCenter ); - return true; -} - - void PlaylistView::onDeleted() { @@ -174,7 +164,6 @@ PlaylistView::onMenuTriggered( int action ) break; default: - TrackView::onMenuTriggered( action ); break; } } diff --git a/src/libtomahawk/playlist/PlaylistView.h b/src/libtomahawk/playlist/PlaylistView.h index 34633ee1e..e3cbbcf53 100644 --- a/src/libtomahawk/playlist/PlaylistView.h +++ b/src/libtomahawk/playlist/PlaylistView.h @@ -26,7 +26,7 @@ #include "ViewPage.h" #include "DllMacro.h" -class DLLEXPORT PlaylistView : public TrackView, public Tomahawk::ViewPage +class DLLEXPORT PlaylistView : public TrackView { Q_OBJECT @@ -38,17 +38,9 @@ public: virtual void setPlaylistModel( PlaylistModel* model ); virtual void setModel( QAbstractItemModel* model ); - virtual QWidget* widget() { return this; } - virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } - - virtual bool showFilter() const { return true; } - virtual QList updaters() const; - virtual QString title() const { return playlistModel()->title(); } - virtual QString description() const { return m_model->description(); } virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/playlist-icon.png" ); } - virtual bool jumpToCurrentTrack(); virtual bool isTemporaryPage() const; signals: From 872ccc53052e4129d59d42cdeada84c0df074108 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:47:54 +0200 Subject: [PATCH 218/433] * A Source's latest-additions view is now a TrackView instead of a CollectionView. --- src/sourcetree/items/SourceItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcetree/items/SourceItem.cpp b/src/sourcetree/items/SourceItem.cpp index 5df62ad39..3b0491372 100644 --- a/src/sourcetree/items/SourceItem.cpp +++ b/src/sourcetree/items/SourceItem.cpp @@ -528,7 +528,7 @@ SourceItem::latestAdditionsClicked() { if ( !m_latestAdditionsPage ) { - CollectionView* cv = new CollectionView( ViewManager::instance()->widget() ); + TrackView* cv = new TrackView( ViewManager::instance()->widget() ); cv->setFrameShape( QFrame::NoFrame ); cv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); From e197231fe60671e10806e090ff0ba578eb30292a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:57:42 +0200 Subject: [PATCH 219/433] * CollectionView is gone. --- src/libtomahawk/ViewManager.cpp | 17 +---------------- src/libtomahawk/ViewManager.h | 3 --- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index f02e3316d..a66bc63df 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -28,7 +28,6 @@ #include "topbar/TopBar.h" #include "TreeModel.h" -#include "CollectionView.h" #include "PlaylistModel.h" #include "PlaylistView.h" #include "PlayableProxyModel.h" @@ -914,13 +913,6 @@ ViewManager::setTomahawkLoaded() } -ViewPage* -ViewManager::pageForCollection( const collection_ptr& col ) const -{ - return m_collectionViews.value( col ).data(); -} - - ViewPage* ViewManager::pageForDynPlaylist(const dynplaylist_ptr& pl) const { @@ -1001,13 +993,6 @@ ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interf Tomahawk::collection_ptr ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const { - foreach ( QWeakPointer view, m_collectionViews.values() ) - { - if ( view.data()->playlistInterface() == interface ) - { - return m_collectionViews.key( view ); - } - } foreach ( QWeakPointer view, m_collectionAlbumViews.values() ) { if ( view.data()->playlistInterface() == interface ) @@ -1041,7 +1026,7 @@ ViewManager::showCurrentTrack() // reset the correct mode, if the user has changed it since - if ( dynamic_cast< CollectionView* >( page ) ) + if ( dynamic_cast< TrackView* >( page ) ) m_currentMode = PlaylistModes::Flat; else if ( dynamic_cast< AlbumView* >( page ) ) m_currentMode = PlaylistModes::Album; diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index 78df072ac..c25234900 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -39,7 +39,6 @@ class AlbumInfoWidget; class ArtistInfoWidget; class ArtistView; class CollectionModel; -class CollectionView; class ContextWidget; class PlaylistModel; class PlaylistView; @@ -98,7 +97,6 @@ public: /// Get the view page for the given item. Not pretty... Tomahawk::ViewPage* pageForPlaylist( const Tomahawk::playlist_ptr& pl ) const; Tomahawk::ViewPage* pageForDynPlaylist( const Tomahawk::dynplaylist_ptr& pl ) const; - Tomahawk::ViewPage* pageForCollection( const Tomahawk::collection_ptr& pl ) const; /// Get a playlist (or dynamic playlist ) from a ViewPage* if the page is PlaylistView or DynamicWidget. /// Lives here but used by SourcesModel @@ -217,7 +215,6 @@ private: QList< Tomahawk::collection_ptr > m_superCollections; QHash< Tomahawk::dynplaylist_ptr, QWeakPointer > m_dynamicWidgets; - QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionViews; QHash< Tomahawk::collection_ptr, QWeakPointer > m_treeViews; QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionAlbumViews; QHash< Tomahawk::artist_ptr, QWeakPointer > m_artistViews; From 8c5fbcd7c7d9f58037a77c8ddd7a2e3df9c5d3d4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:58:20 +0200 Subject: [PATCH 220/433] * SourceInfoWidget now uses a bog standard TrackView. --- src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui index e11eeaa15..2af3656d0 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui @@ -76,7 +76,7 @@ - + @@ -117,9 +117,9 @@
    playlist/PlaylistView.h
    - CollectionView + TrackView QTreeView -
    playlist/CollectionView.h
    +
    playlist/TrackView.h
    From bdab8bc1c83a164003b21a3aab836bfb921bbaa8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:58:56 +0200 Subject: [PATCH 221/433] * Need to eventually hookup the link between SourceItem and ViewManager again. --- src/sourcetree/items/SourceItem.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sourcetree/items/SourceItem.cpp b/src/sourcetree/items/SourceItem.cpp index 3b0491372..93f895d41 100644 --- a/src/sourcetree/items/SourceItem.cpp +++ b/src/sourcetree/items/SourceItem.cpp @@ -28,7 +28,6 @@ #include "utils/Logger.h" #include "widgets/SocialPlaylistWidget.h" #include "playlist/CustomPlaylistView.h" -#include "playlist/CollectionView.h" #include "playlist/PlaylistView.h" #include "playlist/RecentlyAddedModel.h" #include "playlist/RecentlyPlayedModel.h" @@ -105,8 +104,8 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw onStationsAdded( stations ); } - if ( ViewManager::instance()->pageForCollection( source->collection() ) ) - model()->linkSourceItemToPage( this, ViewManager::instance()->pageForCollection( source->collection() ) ); +/* if ( ViewManager::instance()->pageForCollection( source->collection() ) ) + model()->linkSourceItemToPage( this, ViewManager::instance()->pageForCollection( source->collection() ) );*/ m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) ); From 35fd077d01cb1b315bbf303505733ad0fab6d5dd Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 04:59:48 +0200 Subject: [PATCH 222/433] * Remove CollectionView which is replaced by TrackView. --- src/libtomahawk/CMakeLists.txt | 1 - src/libtomahawk/playlist/CollectionView.cpp | 98 --------------------- src/libtomahawk/playlist/CollectionView.h | 60 ------------- 3 files changed, 159 deletions(-) delete mode 100644 src/libtomahawk/playlist/CollectionView.cpp delete mode 100644 src/libtomahawk/playlist/CollectionView.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index ee0f0e27d..fa7b7607a 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -50,7 +50,6 @@ set( libGuiSources playlist/TreeProxyModelPlaylistInterface.cpp playlist/TreeHeader.cpp playlist/TreeItemDelegate.cpp - playlist/CollectionView.cpp playlist/PlaylistModel.cpp playlist/PlaylistView.cpp playlist/PlaylistItemDelegate.cpp diff --git a/src/libtomahawk/playlist/CollectionView.cpp b/src/libtomahawk/playlist/CollectionView.cpp deleted file mode 100644 index 5733f4d8f..000000000 --- a/src/libtomahawk/playlist/CollectionView.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "CollectionView.h" - -#include -#include - -#include "PlayableModel.h" -#include "widgets/OverlayWidget.h" -#include "utils/Logger.h" -#include "Source.h" - -using namespace Tomahawk; - - -CollectionView::CollectionView( QWidget* parent ) - : TrackView( parent ) -{ - setProxyModel( new PlayableProxyModel( this ) ); - - setDragDropMode( QAbstractItemView::DragOnly ); -} - - -CollectionView::~CollectionView() -{ - qDebug() << Q_FUNC_INFO; -} - - -void -CollectionView::setModel( QAbstractItemModel* model ) -{ - Q_UNUSED( model ); - qDebug() << "Explicitly use setPlayableModel instead"; - Q_ASSERT( false ); -} - - -void -CollectionView::setPlayableModel( PlayableModel* model ) -{ - TrackView::setPlayableModel( model ); - - setColumnHidden( PlayableModel::Score, true ); // Hide score column per default - setColumnHidden( PlayableModel::Origin, true ); // Hide origin column per default - setColumnHidden( PlayableModel::Composer, true ); //Hide composer column per default - - setGuid( QString( "collectionview/%1" ).arg( model->columnCount() ) ); - sortByColumn( PlayableModel::Artist, Qt::AscendingOrder ); - - connect( model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); -} - - -void -CollectionView::dragEnterEvent( QDragEnterEvent* event ) -{ - event->ignore(); -} - - -void -CollectionView::onTrackCountChanged( unsigned int tracks ) -{ - if ( tracks == 0 ) - { - overlay()->setText( tr( "This collection is empty." ) ); - overlay()->show(); - } - else - overlay()->hide(); -} - - -bool -CollectionView::jumpToCurrentTrack() -{ - scrollTo( proxyModel()->currentIndex(), QAbstractItemView::PositionAtCenter ); - return true; -} diff --git a/src/libtomahawk/playlist/CollectionView.h b/src/libtomahawk/playlist/CollectionView.h deleted file mode 100644 index 40f3ac76f..000000000 --- a/src/libtomahawk/playlist/CollectionView.h +++ /dev/null @@ -1,60 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2012, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef COLLECTIONVIEW_H -#define COLLECTIONVIEW_H - -#include "PlayableModel.h" -#include "PlayableProxyModel.h" -#include "TrackView.h" -#include "ViewPage.h" - -#include "DllMacro.h" - -class DLLEXPORT CollectionView : public TrackView, public Tomahawk::ViewPage -{ -Q_OBJECT - -public: - explicit CollectionView( QWidget* parent = 0 ); - ~CollectionView(); - - virtual void setPlayableModel( PlayableModel* model ); - virtual void setModel( QAbstractItemModel* model ); - - virtual QWidget* widget() { return this; } - virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } - - virtual QString title() const { return model()->title(); } - virtual QString description() const { return model()->description(); } - virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/music-icon.png" ); } - - virtual bool showModes() const { return true; } - virtual bool showFilter() const { return true; } - - virtual bool jumpToCurrentTrack(); - -private slots: - void onTrackCountChanged( unsigned int tracks ); - -protected: - virtual void dragEnterEvent( QDragEnterEvent* event ); -}; - -#endif // COLLECTIONVIEW_H From 6d9b41dc021a6e7ca941c3308621417af00aad30 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 05:18:51 +0200 Subject: [PATCH 223/433] * Soon to be used. --- src/libtomahawk/playlist/ArtistView.cpp | 7 +++++++ src/libtomahawk/playlist/{AlbumView.cpp => GridView.cpp} | 0 src/libtomahawk/playlist/{AlbumView.h => GridView.h} | 0 3 files changed, 7 insertions(+) rename src/libtomahawk/playlist/{AlbumView.cpp => GridView.cpp} (100%) rename src/libtomahawk/playlist/{AlbumView.h => GridView.h} (100%) diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/ArtistView.cpp index d21dccf4e..7d04c7020 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/ArtistView.cpp @@ -157,6 +157,13 @@ ArtistView::setTreeModel( TreeModel* model ) } emit modelChanged(); + +/* setColumnHidden( PlayableModel::Score, true ); // Hide score column per default + setColumnHidden( PlayableModel::Origin, true ); // Hide origin column per default + setColumnHidden( PlayableModel::Composer, true ); //Hide composer column per default + + setGuid( QString( "collectionview/%1" ).arg( model->columnCount() ) ); + sortByColumn( PlayableModel::Artist, Qt::AscendingOrder );*/ } diff --git a/src/libtomahawk/playlist/AlbumView.cpp b/src/libtomahawk/playlist/GridView.cpp similarity index 100% rename from src/libtomahawk/playlist/AlbumView.cpp rename to src/libtomahawk/playlist/GridView.cpp diff --git a/src/libtomahawk/playlist/AlbumView.h b/src/libtomahawk/playlist/GridView.h similarity index 100% rename from src/libtomahawk/playlist/AlbumView.h rename to src/libtomahawk/playlist/GridView.h From a61f60285549f94c252d53db79a41fe2bf709a50 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 05:19:43 +0200 Subject: [PATCH 224/433] * Renamed AlbumView to GridView. --- src/libtomahawk/CMakeLists.txt | 2 +- src/libtomahawk/ViewManager.cpp | 30 +++++++++---------- src/libtomahawk/ViewManager.h | 6 ++-- .../playlist/AlbumItemDelegate.cpp | 4 +-- src/libtomahawk/playlist/GridView.cpp | 30 +++++++++---------- src/libtomahawk/playlist/GridView.h | 12 ++++---- src/libtomahawk/widgets/NewReleasesWidget.ui | 6 ++-- src/libtomahawk/widgets/SearchWidget.ui | 8 ++--- .../widgets/SocialPlaylistWidget.ui | 6 ++-- src/libtomahawk/widgets/WelcomeWidget.ui | 6 ++-- src/libtomahawk/widgets/WhatsHotWidget.ui | 6 ++-- .../widgets/infowidgets/AlbumInfoWidget.ui | 6 ++-- .../widgets/infowidgets/ArtistInfoWidget.ui | 8 ++--- .../widgets/infowidgets/SourceInfoWidget.ui | 6 ++-- .../widgets/infowidgets/TrackInfoWidget.ui | 6 ++-- 15 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index fa7b7607a..1bd3e92c8 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -62,7 +62,7 @@ set( libGuiSources playlist/TrackHeader.cpp playlist/AlbumModel.cpp playlist/AlbumItemDelegate.cpp - playlist/AlbumView.cpp + playlist/GridView.cpp playlist/ArtistView.cpp playlist/CustomPlaylistView.cpp playlist/ViewHeader.cpp diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index a66bc63df..d2543b6ac 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -33,7 +33,7 @@ #include "PlayableProxyModel.h" #include "PlayableModel.h" #include "ArtistView.h" -#include "AlbumView.h" +#include "GridView.h" #include "AlbumModel.h" #include "SourceList.h" #include "TomahawkSettings.h" @@ -99,9 +99,9 @@ ViewManager::ViewManager( QObject* parent ) m_superCollectionView->setShowModes( false ); // m_superCollectionView->proxyModel()->setShowOfflineResults( false ); - m_superAlbumView = new AlbumView(); - m_superAlbumModel = new AlbumModel( m_superAlbumView ); - m_superAlbumView->setPlayableModel( m_superAlbumModel ); + m_superGridView = new GridView(); + m_superAlbumModel = new AlbumModel( m_superGridView ); + m_superGridView->setPlayableModel( m_superAlbumModel ); m_stack->setContentsMargins( 0, 0, 0, 0 ); m_widget->setContentsMargins( 0, 0, 0, 0 ); @@ -321,19 +321,19 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) if ( m_currentMode == PlaylistModes::Album ) { - AlbumView* aview; - if ( !m_collectionAlbumViews.contains( collection ) || m_collectionAlbumViews.value( collection ).isNull() ) + GridView* aview; + if ( !m_collectionGridViews.contains( collection ) || m_collectionGridViews.value( collection ).isNull() ) { - aview = new AlbumView(); + aview = new GridView(); AlbumModel* amodel = new AlbumModel( aview ); aview->setPlayableModel( amodel ); amodel->addCollection( collection ); - m_collectionAlbumViews.insert( collection, aview ); + m_collectionGridViews.insert( collection, aview ); } else { - aview = m_collectionAlbumViews.value( collection ).data(); + aview = m_collectionGridViews.value( collection ).data(); } shown = aview; @@ -406,8 +406,8 @@ ViewManager::showSuperCollection() } else if ( m_currentMode == PlaylistModes::Album ) { - shown = m_superAlbumView; - setPage( m_superAlbumView ); + shown = m_superGridView; + setPage( m_superGridView ); } emit numSourcesChanged( m_superCollections.count() ); @@ -993,11 +993,11 @@ ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interf Tomahawk::collection_ptr ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const { - foreach ( QWeakPointer view, m_collectionAlbumViews.values() ) + foreach ( QWeakPointer view, m_collectionGridViews.values() ) { if ( view.data()->playlistInterface() == interface ) { - return m_collectionAlbumViews.key( view ); + return m_collectionGridViews.key( view ); } } @@ -1010,7 +1010,7 @@ ViewManager::isSuperCollectionVisible() const { return ( currentPage() != 0 && ( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() || - currentPage()->playlistInterface() == m_superAlbumView->playlistInterface() ) ); + currentPage()->playlistInterface() == m_superGridView->playlistInterface() ) ); } @@ -1028,7 +1028,7 @@ ViewManager::showCurrentTrack() if ( dynamic_cast< TrackView* >( page ) ) m_currentMode = PlaylistModes::Flat; - else if ( dynamic_cast< AlbumView* >( page ) ) + else if ( dynamic_cast< GridView* >( page ) ) m_currentMode = PlaylistModes::Album; else if ( dynamic_cast< ArtistView* >( page ) ) m_currentMode = PlaylistModes::Tree; diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index c25234900..50ab8ae85 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -34,7 +34,7 @@ class AnimatedSplitter; class AlbumModel; -class AlbumView; +class GridView; class AlbumInfoWidget; class ArtistInfoWidget; class ArtistView; @@ -202,7 +202,7 @@ private: AnimatedSplitter* m_splitter; AlbumModel* m_superAlbumModel; - AlbumView* m_superAlbumView; + GridView* m_superGridView; TreeModel* m_superCollectionModel; ArtistView* m_superCollectionView; QueueView* m_queue; @@ -216,7 +216,7 @@ private: QHash< Tomahawk::dynplaylist_ptr, QWeakPointer > m_dynamicWidgets; QHash< Tomahawk::collection_ptr, QWeakPointer > m_treeViews; - QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionAlbumViews; + QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionGridViews; QHash< Tomahawk::artist_ptr, QWeakPointer > m_artistViews; QHash< Tomahawk::album_ptr, QWeakPointer > m_albumViews; QHash< Tomahawk::query_ptr, QWeakPointer > m_trackViews; diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/AlbumItemDelegate.cpp index 949b439fb..b160a1dee 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/AlbumItemDelegate.cpp @@ -37,7 +37,7 @@ #include "playlist/PlayableItem.h" #include "playlist/PlayableProxyModel.h" -#include "AlbumView.h" +#include "GridView.h" #include "ViewManager.h" #include "utils/AnimatedSpinner.h" #include "widgets/ImageButton.h" @@ -406,7 +406,7 @@ AlbumItemDelegate::modelChanged() widget->deleteLater(); m_spinner.clear(); - if ( AlbumView* view = qobject_cast< AlbumView* >( m_view ) ) + if ( GridView* view = qobject_cast< GridView* >( m_view ) ) m_model = view->proxyModel(); } diff --git a/src/libtomahawk/playlist/GridView.cpp b/src/libtomahawk/playlist/GridView.cpp index 963812375..4b196e1c9 100644 --- a/src/libtomahawk/playlist/GridView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -17,7 +17,7 @@ * along with Tomahawk. If not, see . */ -#include "AlbumView.h" +#include "GridView.h" #include #include @@ -45,7 +45,7 @@ using namespace Tomahawk; -AlbumView::AlbumView( QWidget* parent ) +GridView::GridView( QWidget* parent ) : QListView( parent ) , m_model( 0 ) , m_proxyModel( 0 ) @@ -88,14 +88,14 @@ AlbumView::AlbumView( QWidget* parent ) } -AlbumView::~AlbumView() +GridView::~GridView() { qDebug() << Q_FUNC_INFO; } void -AlbumView::setProxyModel( PlayableProxyModel* model ) +GridView::setProxyModel( PlayableProxyModel* model ) { m_proxyModel = model; m_delegate = new AlbumItemDelegate( this, m_proxyModel ); @@ -107,7 +107,7 @@ AlbumView::setProxyModel( PlayableProxyModel* model ) void -AlbumView::setModel( QAbstractItemModel* model ) +GridView::setModel( QAbstractItemModel* model ) { Q_UNUSED( model ); qDebug() << "Explicitly use setAlbumModel instead"; @@ -116,7 +116,7 @@ AlbumView::setModel( QAbstractItemModel* model ) void -AlbumView::setPlayableModel( PlayableModel* model ) +GridView::setPlayableModel( PlayableModel* model ) { m_inited = false; m_model = model; @@ -134,7 +134,7 @@ AlbumView::setPlayableModel( PlayableModel* model ) void -AlbumView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) +GridView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { QListView::currentChanged( current, previous ); @@ -148,7 +148,7 @@ AlbumView::currentChanged( const QModelIndex& current, const QModelIndex& previo void -AlbumView::onItemActivated( const QModelIndex& index ) +GridView::onItemActivated( const QModelIndex& index ) { PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); if ( item ) @@ -167,7 +167,7 @@ AlbumView::onItemActivated( const QModelIndex& index ) void -AlbumView::scrollContentsBy( int dx, int dy ) +GridView::scrollContentsBy( int dx, int dy ) { QListView::scrollContentsBy( dx, dy ); emit scrolledContents( dx, dy ); @@ -175,7 +175,7 @@ AlbumView::scrollContentsBy( int dx, int dy ) void -AlbumView::paintEvent( QPaintEvent* event ) +GridView::paintEvent( QPaintEvent* event ) { if ( !autoFitItems() || m_inited || !m_proxyModel->rowCount() ) QListView::paintEvent( event ); @@ -183,7 +183,7 @@ AlbumView::paintEvent( QPaintEvent* event ) void -AlbumView::resizeEvent( QResizeEvent* event ) +GridView::resizeEvent( QResizeEvent* event ) { QListView::resizeEvent( event ); layoutItems(); @@ -191,7 +191,7 @@ AlbumView::resizeEvent( QResizeEvent* event ) void -AlbumView::layoutItems() +GridView::layoutItems() { if ( autoFitItems() && m_model ) { @@ -225,7 +225,7 @@ AlbumView::layoutItems() void -AlbumView::onFilterChanged( const QString& ) +GridView::onFilterChanged( const QString& ) { if ( selectedIndexes().count() ) scrollTo( selectedIndexes().at( 0 ), QAbstractItemView::PositionAtCenter ); @@ -233,7 +233,7 @@ AlbumView::onFilterChanged( const QString& ) void -AlbumView::startDrag( Qt::DropActions supportedActions ) +GridView::startDrag( Qt::DropActions supportedActions ) { QList pindexes; QModelIndexList indexes; @@ -265,7 +265,7 @@ AlbumView::startDrag( Qt::DropActions supportedActions ) void -AlbumView::onCustomContextMenu( const QPoint& pos ) +GridView::onCustomContextMenu( const QPoint& pos ) { m_contextMenu->clear(); diff --git a/src/libtomahawk/playlist/GridView.h b/src/libtomahawk/playlist/GridView.h index 3ca7b8d46..715183d66 100644 --- a/src/libtomahawk/playlist/GridView.h +++ b/src/libtomahawk/playlist/GridView.h @@ -17,8 +17,8 @@ * along with Tomahawk. If not, see . */ -#ifndef ALBUMVIEW_H -#define ALBUMVIEW_H +#ifndef GRIDVIEW_H +#define GRIDVIEW_H #include #include @@ -38,13 +38,13 @@ class AnimatedSpinner; class AlbumItemDelegate; class PlayableModel; -class DLLEXPORT AlbumView : public QListView, public Tomahawk::ViewPage +class DLLEXPORT GridView : public QListView, public Tomahawk::ViewPage { Q_OBJECT public: - explicit AlbumView( QWidget* parent = 0 ); - ~AlbumView(); + explicit GridView( QWidget* parent = 0 ); + ~GridView(); void setProxyModel( PlayableProxyModel* model ); @@ -106,4 +106,4 @@ private: QRect m_paintRect; }; -#endif // ALBUMVIEW_H +#endif // GRIDVIEW_H diff --git a/src/libtomahawk/widgets/NewReleasesWidget.ui b/src/libtomahawk/widgets/NewReleasesWidget.ui index 1dc057717..f1e8a1b9e 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.ui +++ b/src/libtomahawk/widgets/NewReleasesWidget.ui @@ -16,7 +16,7 @@ - + true @@ -29,9 +29,9 @@ - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    Tomahawk::Breadcrumb diff --git a/src/libtomahawk/widgets/SearchWidget.ui b/src/libtomahawk/widgets/SearchWidget.ui index d1f81af0c..e2df0a078 100644 --- a/src/libtomahawk/widgets/SearchWidget.ui +++ b/src/libtomahawk/widgets/SearchWidget.ui @@ -29,8 +29,8 @@ 1 - - + + @@ -44,9 +44,9 @@
    playlist/PlaylistView.h
    - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    diff --git a/src/libtomahawk/widgets/SocialPlaylistWidget.ui b/src/libtomahawk/widgets/SocialPlaylistWidget.ui index bf1015e98..1dfc5327b 100644 --- a/src/libtomahawk/widgets/SocialPlaylistWidget.ui +++ b/src/libtomahawk/widgets/SocialPlaylistWidget.ui @@ -36,7 +36,7 @@
    - + @@ -92,9 +92,9 @@
    widgets/HeaderLabel.h
    - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    PlaylistWidget diff --git a/src/libtomahawk/widgets/WelcomeWidget.ui b/src/libtomahawk/widgets/WelcomeWidget.ui index a46ad774f..e91e39612 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.ui +++ b/src/libtomahawk/widgets/WelcomeWidget.ui @@ -36,7 +36,7 @@ - + true @@ -94,9 +94,9 @@
    widgets/HeaderLabel.h
    - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    PlaylistView diff --git a/src/libtomahawk/widgets/WhatsHotWidget.ui b/src/libtomahawk/widgets/WhatsHotWidget.ui index 95e51f4d3..b684f1566 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.ui +++ b/src/libtomahawk/widgets/WhatsHotWidget.ui @@ -47,7 +47,7 @@ - + true @@ -64,9 +64,9 @@ - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    ArtistView diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui index 9ad34c135..61107dc20 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui @@ -33,7 +33,7 @@
    - +
    @@ -53,9 +53,9 @@
    ArtistView.h
    - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index d7ca40046..e882b823b 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -57,7 +57,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -114,9 +114,9 @@
    ArtistView.h
    - AlbumView + GridView QListView -
    AlbumView.h
    +
    GridView.h
    diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui index 2af3656d0..de7638fff 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.ui @@ -32,7 +32,7 @@ - + 0 @@ -107,9 +107,9 @@
    widgets/HeaderLabel.h
    - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    PlaylistView diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui index 4814e2de0..8aeba01e2 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui @@ -208,7 +208,7 @@
    - + 0 @@ -224,9 +224,9 @@ - AlbumView + GridView QListView -
    playlist/AlbumView.h
    +
    playlist/GridView.h
    HeaderLabel From 75991dca18c646b5ebb1265f4d34a1f3c54952d5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 05:29:02 +0200 Subject: [PATCH 225/433] * Renamed AlbumItemDelegate to GridItemDelegate. --- src/libtomahawk/CMakeLists.txt | 2 +- ...mItemDelegate.cpp => GridItemDelegate.cpp} | 40 +++++++++---------- ...AlbumItemDelegate.h => GridItemDelegate.h} | 10 ++--- src/libtomahawk/playlist/GridView.cpp | 4 +- src/libtomahawk/playlist/GridView.h | 4 +- 5 files changed, 30 insertions(+), 30 deletions(-) rename src/libtomahawk/playlist/{AlbumItemDelegate.cpp => GridItemDelegate.cpp} (90%) rename src/libtomahawk/playlist/{AlbumItemDelegate.h => GridItemDelegate.h} (92%) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 1bd3e92c8..80c39e1fd 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -61,7 +61,7 @@ set( libGuiSources playlist/TrackView.cpp playlist/TrackHeader.cpp playlist/AlbumModel.cpp - playlist/AlbumItemDelegate.cpp + playlist/GridItemDelegate.cpp playlist/GridView.cpp playlist/ArtistView.cpp playlist/CustomPlaylistView.cpp diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.cpp b/src/libtomahawk/playlist/GridItemDelegate.cpp similarity index 90% rename from src/libtomahawk/playlist/AlbumItemDelegate.cpp rename to src/libtomahawk/playlist/GridItemDelegate.cpp index b160a1dee..4568c1705 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.cpp +++ b/src/libtomahawk/playlist/GridItemDelegate.cpp @@ -17,7 +17,7 @@ * along with Tomahawk. If not, see . */ -#include "AlbumItemDelegate.h" +#include "GridItemDelegate.h" #include #include @@ -48,7 +48,7 @@ namespace { }; -AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, PlayableProxyModel* proxy ) +GridItemDelegate::GridItemDelegate( QAbstractItemView* parent, PlayableProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) , m_view( parent ) , m_model( proxy ) @@ -61,7 +61,7 @@ AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, PlayableProxyMo QSize -AlbumItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +GridItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { QSize size = QStyledItemDelegate::sizeHint( option, index ); return size; @@ -69,7 +69,7 @@ AlbumItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelInd void -AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); if ( !item ) @@ -116,7 +116,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, m_covers.insert( index, QSharedPointer< Tomahawk::PixmapDelegateFader >( new Tomahawk::PixmapDelegateFader( item->query(), r.size(), TomahawkUtils::Grid ) ) ); } - _detail::Closure* closure = NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ), const_cast(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + _detail::Closure* closure = NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ), const_cast(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); closure->setAutoDelete( false ); } @@ -218,7 +218,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, void -AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) +GridItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) { QPoint pos = m_playButton[ index ]->pos(); foreach ( ImageButton* button, m_playButton ) @@ -240,10 +240,10 @@ AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) _detail::Closure* closure; closure = NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), - const_cast(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + const_cast(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); closure = NewClosure( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), - const_cast(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + const_cast(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); closure->setAutoDelete( false ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackFinished() ) ); @@ -259,7 +259,7 @@ AlbumItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) bool -AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ) +GridItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ) { Q_UNUSED( model ); Q_UNUSED( option ); @@ -308,7 +308,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const button->show(); NewClosure( button, SIGNAL( clicked( bool ) ), - const_cast(this), SLOT( onPlayClicked( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); + const_cast(this), SLOT( onPlayClicked( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); m_playButton[ index ] = button; } @@ -390,7 +390,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const void -AlbumItemDelegate::modelChanged() +GridItemDelegate::modelChanged() { m_artistNameRects.clear(); m_hoveringOver = QPersistentModelIndex(); @@ -412,7 +412,7 @@ AlbumItemDelegate::modelChanged() void -AlbumItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx ) +GridItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx ) { if ( !idx.isValid() ) return; @@ -421,7 +421,7 @@ AlbumItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx ) void -AlbumItemDelegate::onScrolled( int dx, int dy ) +GridItemDelegate::onScrolled( int dx, int dy ) { foreach ( QWidget* widget, m_spinner.values() ) { @@ -439,7 +439,7 @@ AlbumItemDelegate::onScrolled( int dx, int dy ) void -AlbumItemDelegate::onPlaybackFinished() +GridItemDelegate::onPlaybackFinished() { foreach ( ImageButton* button, m_pauseButton ) button->deleteLater(); @@ -448,7 +448,7 @@ AlbumItemDelegate::onPlaybackFinished() void -AlbumItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) +GridItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) { PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) ); if ( item ) @@ -484,7 +484,7 @@ AlbumItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index ) void -AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) +GridItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) { if ( !m_spinner.contains( index ) ) return; @@ -513,14 +513,14 @@ AlbumItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) void -AlbumItemDelegate::fadingFrameChanged( const QPersistentModelIndex& idx ) +GridItemDelegate::fadingFrameChanged( const QPersistentModelIndex& idx ) { emit updateIndex( idx ); } void -AlbumItemDelegate::fadingFrameFinished( const QPersistentModelIndex& idx ) +GridItemDelegate::fadingFrameFinished( const QPersistentModelIndex& idx ) { if ( m_hoverFaders.contains( idx ) ) { @@ -531,7 +531,7 @@ AlbumItemDelegate::fadingFrameFinished( const QPersistentModelIndex& idx ) QTimeLine* -AlbumItemDelegate::createTimeline( QTimeLine::Direction direction ) +GridItemDelegate::createTimeline( QTimeLine::Direction direction ) { QTimeLine* timeline = new QTimeLine( FADE_DURATION, this ); timeline->setDirection( direction ); @@ -545,7 +545,7 @@ AlbumItemDelegate::createTimeline( QTimeLine::Direction direction ) bool -AlbumItemDelegate::eventFilter( QObject* obj, QEvent* event ) +GridItemDelegate::eventFilter( QObject* obj, QEvent* event ) { if ( event->type() == QEvent::Wheel ) { diff --git a/src/libtomahawk/playlist/AlbumItemDelegate.h b/src/libtomahawk/playlist/GridItemDelegate.h similarity index 92% rename from src/libtomahawk/playlist/AlbumItemDelegate.h rename to src/libtomahawk/playlist/GridItemDelegate.h index 81eace7cd..d2caa9999 100644 --- a/src/libtomahawk/playlist/AlbumItemDelegate.h +++ b/src/libtomahawk/playlist/GridItemDelegate.h @@ -17,8 +17,8 @@ * along with Tomahawk. If not, see . */ -#ifndef ALBUMITEMDELEGATE_H -#define ALBUMITEMDELEGATE_H +#ifndef GRIDITEMDELEGATE_H +#define GRIDITEMDELEGATE_H #include #include @@ -34,12 +34,12 @@ class QTimeLine; class PlayableProxyModel; class ImageButton; -class DLLEXPORT AlbumItemDelegate : public QStyledItemDelegate +class DLLEXPORT GridItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - AlbumItemDelegate( QAbstractItemView* parent = 0, PlayableProxyModel* proxy = 0 ); + GridItemDelegate( QAbstractItemView* parent = 0, PlayableProxyModel* proxy = 0 ); protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -85,4 +85,4 @@ private: mutable QHash< QPersistentModelIndex, QTimeLine* > m_hoverFaders; }; -#endif // ALBUMITEMDELEGATE_H +#endif // GRIDITEMDELEGATE_H diff --git a/src/libtomahawk/playlist/GridView.cpp b/src/libtomahawk/playlist/GridView.cpp index 4b196e1c9..7615e0edc 100644 --- a/src/libtomahawk/playlist/GridView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -31,7 +31,7 @@ #include "Artist.h" #include "Source.h" #include "PlayableItem.h" -#include "AlbumItemDelegate.h" +#include "GridItemDelegate.h" #include "AlbumModel.h" #include "PlayableModel.h" #include "ContextMenu.h" @@ -98,7 +98,7 @@ void GridView::setProxyModel( PlayableProxyModel* model ) { m_proxyModel = model; - m_delegate = new AlbumItemDelegate( this, m_proxyModel ); + m_delegate = new GridItemDelegate( this, m_proxyModel ); connect( m_delegate, SIGNAL( updateIndex( QModelIndex ) ), this, SLOT( update( QModelIndex ) ) ); setItemDelegate( m_delegate ); diff --git a/src/libtomahawk/playlist/GridView.h b/src/libtomahawk/playlist/GridView.h index 715183d66..f6ceb19e3 100644 --- a/src/libtomahawk/playlist/GridView.h +++ b/src/libtomahawk/playlist/GridView.h @@ -35,7 +35,7 @@ namespace Tomahawk }; class AnimatedSpinner; -class AlbumItemDelegate; +class GridItemDelegate; class PlayableModel; class DLLEXPORT GridView : public QListView, public Tomahawk::ViewPage @@ -93,7 +93,7 @@ private slots: private: PlayableModel* m_model; PlayableProxyModel* m_proxyModel; - AlbumItemDelegate* m_delegate; + GridItemDelegate* m_delegate; AnimatedSpinner* m_loadingSpinner; OverlayWidget* m_overlay; From 59fb1fefa095fda21a89fc48a10d0a921b92df54 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 05:44:56 +0200 Subject: [PATCH 226/433] * Got rid of TrackHeader. Handled by ViewHeader now. --- src/libtomahawk/CMakeLists.txt | 1 - .../context/pages/TopTracksContext.cpp | 1 - src/libtomahawk/playlist/PlayableModel.cpp | 27 +++++++++++++ src/libtomahawk/playlist/PlayableModel.h | 2 + .../playlist/PlaylistChartItemDelegate.cpp | 2 +- .../playlist/PlaylistItemDelegate.cpp | 2 +- .../playlist/PlaylistLargeItemDelegate.cpp | 2 +- src/libtomahawk/playlist/TrackHeader.cpp | 39 ------------------ src/libtomahawk/playlist/TrackHeader.h | 40 ------------------- src/libtomahawk/playlist/TrackView.cpp | 5 ++- src/libtomahawk/playlist/TrackView.h | 6 +-- .../playlist/dynamic/DynamicView.cpp | 1 - .../widgets/infowidgets/ArtistInfoWidget.cpp | 1 - 13 files changed, 38 insertions(+), 91 deletions(-) delete mode 100644 src/libtomahawk/playlist/TrackHeader.cpp delete mode 100644 src/libtomahawk/playlist/TrackHeader.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 80c39e1fd..63cced25f 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -59,7 +59,6 @@ set( libGuiSources playlist/PlayableProxyModel.cpp playlist/PlayableProxyModelPlaylistInterface.cpp playlist/TrackView.cpp - playlist/TrackHeader.cpp playlist/AlbumModel.cpp playlist/GridItemDelegate.cpp playlist/GridView.cpp diff --git a/src/libtomahawk/context/pages/TopTracksContext.cpp b/src/libtomahawk/context/pages/TopTracksContext.cpp index 2635f7c2b..a8df51fe3 100644 --- a/src/libtomahawk/context/pages/TopTracksContext.cpp +++ b/src/libtomahawk/context/pages/TopTracksContext.cpp @@ -21,7 +21,6 @@ #include "playlist/PlaylistModel.h" #include "playlist/PlaylistView.h" -#include "playlist/TrackHeader.h" #include "Source.h" using namespace Tomahawk; diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index d2b7e3f97..b6c7347a2 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -735,6 +735,33 @@ PlayableModel::setStyle( PlayableModel::PlayableItemStyle style ) } +QList< double > +PlayableModel::columnWeights() const +{ + QList< double > w; + + switch ( m_style ) + { + case Short: + case ShortWithAvatars: + case Large: + w << 1.0; + break; + + case Collection: + w << 0.42 << 0.12 << 0.07 << 0.07 << 0.07 << 0.07 << 0.07; // << 0.11; + break; + + case Detailed: + default: + w << 0.16 << 0.16 << 0.14 << 0.12 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.09; // << 0.03; + break; + } + + return w; +} + + Qt::Alignment PlayableModel::columnAlignment( int column ) const { diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 425496abf..4a219dee6 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -87,6 +87,8 @@ public: virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; virtual bool hasChildren( const QModelIndex& parent ) const; + QList< double > columnWeights() const; + virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; diff --git a/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp index 638d88a4b..b36058e94 100644 --- a/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp @@ -32,7 +32,7 @@ #include "PlayableItem.h" #include "PlayableProxyModel.h" #include "TrackView.h" -#include "TrackHeader.h" +#include "ViewHeader.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" diff --git a/src/libtomahawk/playlist/PlaylistItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistItemDelegate.cpp index 3fa898c2f..494b683f7 100644 --- a/src/libtomahawk/playlist/PlaylistItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistItemDelegate.cpp @@ -32,7 +32,7 @@ #include "PlayableItem.h" #include "PlayableProxyModel.h" #include "TrackView.h" -#include "TrackHeader.h" +#include "ViewHeader.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp index acd1fd8f0..1ca6b793f 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -33,7 +33,7 @@ #include "PlayableItem.h" #include "PlayableProxyModel.h" #include "TrackView.h" -#include "TrackHeader.h" +#include "ViewHeader.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" diff --git a/src/libtomahawk/playlist/TrackHeader.cpp b/src/libtomahawk/playlist/TrackHeader.cpp deleted file mode 100644 index 74ccf1ff2..000000000 --- a/src/libtomahawk/playlist/TrackHeader.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "TrackHeader.h" - -#include "playlist/TrackView.h" -#include "utils/Logger.h" - - -TrackHeader::TrackHeader( TrackView* parent ) - : ViewHeader( parent ) - , m_parent( parent ) -{ - QList< double > columnWeights; - columnWeights << 0.16 << 0.16 << 0.14 << 0.12 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.09; // << 0.03; - - setDefaultColumnWeights( columnWeights ); -} - - -TrackHeader::~TrackHeader() -{ -} diff --git a/src/libtomahawk/playlist/TrackHeader.h b/src/libtomahawk/playlist/TrackHeader.h deleted file mode 100644 index 2c472dcfd..000000000 --- a/src/libtomahawk/playlist/TrackHeader.h +++ /dev/null @@ -1,40 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * Copyright 2010-2011, Jeff Mitchell - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef TRACKHEADER_H -#define TRACKHEADER_H - -#include "ViewHeader.h" -#include "DllMacro.h" - -class TrackView; - -class DLLEXPORT TrackHeader : public ViewHeader -{ -Q_OBJECT - -public: - explicit TrackHeader( TrackView* parent = 0 ); - ~TrackHeader(); - -private: - TrackView* m_parent; -}; - -#endif diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index 9a5d0e827..5eb8991f3 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -23,7 +23,7 @@ #include #include -#include "TrackHeader.h" +#include "ViewHeader.h" #include "ViewManager.h" #include "PlayableModel.h" #include "PlayableProxyModel.h" @@ -50,7 +50,7 @@ TrackView::TrackView( QWidget* parent ) , m_model( 0 ) , m_proxyModel( 0 ) , m_delegate( 0 ) - , m_header( new TrackHeader( this ) ) + , m_header( new ViewHeader( this ) ) , m_overlay( new OverlayWidget( this ) ) , m_loadingSpinner( new LoadingSpinner( this ) ) , m_resizing( false ) @@ -153,6 +153,7 @@ TrackView::setPlayableModel( PlayableModel* model ) connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); setAcceptDrops( true ); + m_header->setDefaultColumnWeights( model->columnWeights() ); switch( model->style() ) { diff --git a/src/libtomahawk/playlist/TrackView.h b/src/libtomahawk/playlist/TrackView.h index eb6583b22..cab45742d 100644 --- a/src/libtomahawk/playlist/TrackView.h +++ b/src/libtomahawk/playlist/TrackView.h @@ -32,7 +32,7 @@ class QAction; class AnimatedSpinner; -class TrackHeader; +class ViewHeader; class PlayableModel; class PlayableProxyModel; class OverlayWidget; @@ -55,7 +55,7 @@ public: virtual PlayableModel* model() const { return m_model; } PlayableProxyModel* proxyModel() const { return m_proxyModel; } PlaylistItemDelegate* delegate() const { return m_delegate; } - TrackHeader* header() const { return m_header; } + ViewHeader* header() const { return m_header; } OverlayWidget* overlay() const { return m_overlay; } Tomahawk::ContextMenu* contextMenu() const { return m_contextMenu; } AnimatedSpinner* loadingSpinner() const { return m_loadingSpinner; } @@ -131,7 +131,7 @@ private: PlayableModel* m_model; PlayableProxyModel* m_proxyModel; PlaylistItemDelegate* m_delegate; - TrackHeader* m_header; + ViewHeader* m_header; OverlayWidget* m_overlay; AnimatedSpinner* m_loadingSpinner; diff --git a/src/libtomahawk/playlist/dynamic/DynamicView.cpp b/src/libtomahawk/playlist/dynamic/DynamicView.cpp index 06d858f11..a1643195d 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicView.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicView.cpp @@ -27,7 +27,6 @@ #include "PlaylistModel.h" #include "PlayableProxyModel.h" -#include "TrackHeader.h" #include "DynamicModel.h" #include "widgets/OverlayWidget.h" #include "utils/Logger.h" diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 2cd534f88..64d84dfca 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -22,7 +22,6 @@ #include "ui_ArtistInfoWidget.h" #include "audio/AudioEngine.h" -#include "playlist/TrackHeader.h" #include "playlist/PlayableModel.h" #include "playlist/TreeModel.h" #include "playlist/PlaylistModel.h" From d97b83557bb26af761e630805ea6dd5b5a6311a8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 05:46:36 +0200 Subject: [PATCH 227/433] * Got rid of TreeHeader. Handled by ViewHeader now. --- src/libtomahawk/CMakeLists.txt | 1 - src/libtomahawk/playlist/ArtistView.cpp | 5 ++-- src/libtomahawk/playlist/ArtistView.h | 4 +-- src/libtomahawk/playlist/TreeHeader.cpp | 39 ------------------------- src/libtomahawk/playlist/TreeHeader.h | 39 ------------------------- 5 files changed, 5 insertions(+), 83 deletions(-) delete mode 100644 src/libtomahawk/playlist/TreeHeader.cpp delete mode 100644 src/libtomahawk/playlist/TreeHeader.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 63cced25f..5b53750f9 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -48,7 +48,6 @@ set( libGuiSources playlist/TreeModel.cpp playlist/TreeProxyModel.cpp playlist/TreeProxyModelPlaylistInterface.cpp - playlist/TreeHeader.cpp playlist/TreeItemDelegate.cpp playlist/PlaylistModel.cpp playlist/PlaylistView.cpp diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/ArtistView.cpp index 7d04c7020..b62a9f16b 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/ArtistView.cpp @@ -31,7 +31,7 @@ #include "ContextMenu.h" #include "TomahawkSettings.h" -#include "TreeHeader.h" +#include "ViewHeader.h" #include "TreeItemDelegate.h" #include "TreeModel.h" #include "PlayableItem.h" @@ -47,7 +47,7 @@ using namespace Tomahawk; ArtistView::ArtistView( QWidget* parent ) : QTreeView( parent ) - , m_header( new TreeHeader( this ) ) + , m_header( new ViewHeader( this ) ) , m_overlay( new OverlayWidget( this ) ) , m_model( 0 ) , m_proxyModel( 0 ) @@ -145,6 +145,7 @@ ArtistView::setTreeModel( TreeModel* model ) guid(); // this will set the guid on the header + m_header->setDefaultColumnWeights( model->columnWeights() ); if ( model->style() == PlayableModel::Large ) { setHeaderHidden( true ); diff --git a/src/libtomahawk/playlist/ArtistView.h b/src/libtomahawk/playlist/ArtistView.h index f113c78c3..47b01dc36 100644 --- a/src/libtomahawk/playlist/ArtistView.h +++ b/src/libtomahawk/playlist/ArtistView.h @@ -36,7 +36,7 @@ namespace Tomahawk class ContextMenu; }; -class TreeHeader; +class ViewHeader; class AnimatedSpinner; class OverlayWidget; class TreeModel; @@ -106,7 +106,7 @@ private slots: void onMenuTriggered( int action ); private: - TreeHeader* m_header; + ViewHeader* m_header; OverlayWidget* m_overlay; TreeModel* m_model; TreeProxyModel* m_proxyModel; diff --git a/src/libtomahawk/playlist/TreeHeader.cpp b/src/libtomahawk/playlist/TreeHeader.cpp deleted file mode 100644 index 4aeccd17d..000000000 --- a/src/libtomahawk/playlist/TreeHeader.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "TreeHeader.h" - -#include "playlist/ArtistView.h" -#include "utils/Logger.h" -#include "Source.h" - - -TreeHeader::TreeHeader( ArtistView* parent ) - : ViewHeader( parent ) - , m_parent( parent ) -{ - QList< double > columnWeights; - columnWeights << 0.42 << 0.12 << 0.07 << 0.07 << 0.07 << 0.07 << 0.07; // << 0.11; - - setDefaultColumnWeights( columnWeights ); -} - - -TreeHeader::~TreeHeader() -{ -} diff --git a/src/libtomahawk/playlist/TreeHeader.h b/src/libtomahawk/playlist/TreeHeader.h deleted file mode 100644 index d80cf872c..000000000 --- a/src/libtomahawk/playlist/TreeHeader.h +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef TREEHEADER_H -#define TREEHEADER_H - -#include "ViewHeader.h" -#include "DllMacro.h" - -class ArtistView; - -class DLLEXPORT TreeHeader : public ViewHeader -{ -Q_OBJECT - -public: - explicit TreeHeader( ArtistView* parent = 0 ); - ~TreeHeader(); - -private: - ArtistView* m_parent; -}; - -#endif From 0abc1a4be9a4dc75dc013c6481d7e0da75e545b0 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 05:58:42 +0200 Subject: [PATCH 228/433] * Renamed ArtistView to TreeView. --- src/libtomahawk/CMakeLists.txt | 2 +- src/libtomahawk/ViewManager.cpp | 12 +++--- src/libtomahawk/ViewManager.h | 8 ++-- src/libtomahawk/context/ContextWidget.cpp | 2 - .../context/pages/RelatedArtistsContext.cpp | 4 +- .../context/pages/RelatedArtistsContext.h | 4 +- src/libtomahawk/playlist/TreeItemDelegate.cpp | 4 +- src/libtomahawk/playlist/TreeItemDelegate.h | 6 +-- .../playlist/{ArtistView.cpp => TreeView.cpp} | 40 +++++++++---------- .../playlist/{ArtistView.h => TreeView.h} | 12 +++--- src/libtomahawk/widgets/WhatsHotWidget.ui | 6 +-- .../widgets/infowidgets/AlbumInfoWidget.ui | 6 +-- .../widgets/infowidgets/ArtistInfoWidget.ui | 5 --- src/sourcetree/SourcesModel.cpp | 2 +- 14 files changed, 53 insertions(+), 60 deletions(-) rename src/libtomahawk/playlist/{ArtistView.cpp => TreeView.cpp} (93%) rename src/libtomahawk/playlist/{ArtistView.h => TreeView.h} (94%) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 5b53750f9..501d84cc6 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -61,7 +61,7 @@ set( libGuiSources playlist/AlbumModel.cpp playlist/GridItemDelegate.cpp playlist/GridView.cpp - playlist/ArtistView.cpp + playlist/TreeView.cpp playlist/CustomPlaylistView.cpp playlist/ViewHeader.cpp playlist/RecentlyAddedModel.cpp diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index d2543b6ac..35c5970d5 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -32,7 +32,7 @@ #include "PlaylistView.h" #include "PlayableProxyModel.h" #include "PlayableModel.h" -#include "ArtistView.h" +#include "TreeView.h" #include "GridView.h" #include "AlbumModel.h" #include "SourceList.h" @@ -93,7 +93,7 @@ ViewManager::ViewManager( QObject* parent ) m_widget->layout()->addWidget( m_stack ); m_widget->layout()->addWidget( m_contextWidget ); - m_superCollectionView = new ArtistView(); + m_superCollectionView = new TreeView(); m_superCollectionModel = new TreeModel( m_superCollectionView ); m_superCollectionView->setTreeModel( m_superCollectionModel ); m_superCollectionView->setShowModes( false ); @@ -299,10 +299,10 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) if ( m_currentMode == PlaylistModes::Tree ) { - ArtistView* view; + TreeView* view; if ( !m_treeViews.contains( collection ) || m_treeViews.value( collection ).isNull() ) { - view = new ArtistView(); + view = new TreeView(); TreeModel* model = new TreeModel(); view->setTreeModel( model ); @@ -1030,7 +1030,7 @@ ViewManager::showCurrentTrack() m_currentMode = PlaylistModes::Flat; else if ( dynamic_cast< GridView* >( page ) ) m_currentMode = PlaylistModes::Album; - else if ( dynamic_cast< ArtistView* >( page ) ) + else if ( dynamic_cast< TreeView* >( page ) ) m_currentMode = PlaylistModes::Tree; else return; @@ -1075,7 +1075,7 @@ ViewManager::recentPlaysWidget() const } -ArtistView* +TreeView* ViewManager::superCollectionView() const { return m_superCollectionView; diff --git a/src/libtomahawk/ViewManager.h b/src/libtomahawk/ViewManager.h index 50ab8ae85..d4fefe1bf 100644 --- a/src/libtomahawk/ViewManager.h +++ b/src/libtomahawk/ViewManager.h @@ -37,7 +37,7 @@ class AlbumModel; class GridView; class AlbumInfoWidget; class ArtistInfoWidget; -class ArtistView; +class TreeView; class CollectionModel; class ContextWidget; class PlaylistModel; @@ -92,7 +92,7 @@ public: Tomahawk::ViewPage* newReleasesWidget() const; Tomahawk::ViewPage* topLovedWidget() const; Tomahawk::ViewPage* recentPlaysWidget() const; - ArtistView* superCollectionView() const; + TreeView* superCollectionView() const; /// Get the view page for the given item. Not pretty... Tomahawk::ViewPage* pageForPlaylist( const Tomahawk::playlist_ptr& pl ) const; @@ -204,7 +204,7 @@ private: AlbumModel* m_superAlbumModel; GridView* m_superGridView; TreeModel* m_superCollectionModel; - ArtistView* m_superCollectionView; + TreeView* m_superCollectionView; QueueView* m_queue; WelcomeWidget* m_welcomeWidget; WhatsHotWidget* m_whatsHotWidget; @@ -215,7 +215,7 @@ private: QList< Tomahawk::collection_ptr > m_superCollections; QHash< Tomahawk::dynplaylist_ptr, QWeakPointer > m_dynamicWidgets; - QHash< Tomahawk::collection_ptr, QWeakPointer > m_treeViews; + QHash< Tomahawk::collection_ptr, QWeakPointer > m_treeViews; QHash< Tomahawk::collection_ptr, QWeakPointer > m_collectionGridViews; QHash< Tomahawk::artist_ptr, QWeakPointer > m_artistViews; QHash< Tomahawk::album_ptr, QWeakPointer > m_albumViews; diff --git a/src/libtomahawk/context/ContextWidget.cpp b/src/libtomahawk/context/ContextWidget.cpp index ce6b69a05..bbf0e8334 100644 --- a/src/libtomahawk/context/ContextWidget.cpp +++ b/src/libtomahawk/context/ContextWidget.cpp @@ -29,8 +29,6 @@ #include "context/pages/TopTracksContext.h" #include "context/pages/WikipediaContext.h" -#include "playlist/ArtistView.h" -#include "playlist/TreeModel.h" #include "Source.h" #include "utils/StyleHelper.h" diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp index eab2c7d2a..f3a7edd4a 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp @@ -21,7 +21,7 @@ #include -#include "playlist/ArtistView.h" +#include "playlist/TreeView.h" #include "playlist/TreeModel.h" #include "Source.h" @@ -31,7 +31,7 @@ using namespace Tomahawk; RelatedArtistsContext::RelatedArtistsContext() : ContextPage() { - m_relatedView = new ArtistView(); + m_relatedView = new TreeView(); m_relatedView->setGuid( "RelatedArtistsContext" ); m_relatedView->setUpdatesContextView( false ); m_relatedModel = new TreeModel( m_relatedView ); diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.h b/src/libtomahawk/context/pages/RelatedArtistsContext.h index c87b25630..3e45cebce 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.h +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.h @@ -30,7 +30,7 @@ #include "context/ContextPage.h" class TreeModel; -class ArtistView; +class TreeView; class DLLEXPORT RelatedArtistsContext : public Tomahawk::ContextPage { @@ -58,7 +58,7 @@ private slots: void onSimilarArtistsLoaded(); private: - ArtistView* m_relatedView; + TreeView* m_relatedView; TreeModel* m_relatedModel; QGraphicsProxyWidget* m_proxy; diff --git a/src/libtomahawk/playlist/TreeItemDelegate.cpp b/src/libtomahawk/playlist/TreeItemDelegate.cpp index da0b367db..c22847709 100644 --- a/src/libtomahawk/playlist/TreeItemDelegate.cpp +++ b/src/libtomahawk/playlist/TreeItemDelegate.cpp @@ -35,10 +35,10 @@ #include "PlayableItem.h" #include "TreeProxyModel.h" #include "Source.h" -#include "ArtistView.h" +#include "TreeView.h" -TreeItemDelegate::TreeItemDelegate( ArtistView* parent, TreeProxyModel* proxy ) +TreeItemDelegate::TreeItemDelegate( TreeView* parent, TreeProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) , m_view( parent ) , m_model( proxy ) diff --git a/src/libtomahawk/playlist/TreeItemDelegate.h b/src/libtomahawk/playlist/TreeItemDelegate.h index 419bc6790..2c4e90f12 100644 --- a/src/libtomahawk/playlist/TreeItemDelegate.h +++ b/src/libtomahawk/playlist/TreeItemDelegate.h @@ -28,7 +28,7 @@ namespace Tomahawk { class PixmapDelegateFader; } -class ArtistView; +class TreeView; class TreeProxyModel; class DLLEXPORT TreeItemDelegate : public QStyledItemDelegate @@ -36,7 +36,7 @@ class DLLEXPORT TreeItemDelegate : public QStyledItemDelegate Q_OBJECT public: - TreeItemDelegate( ArtistView* parent = 0, TreeProxyModel* proxy = 0 ); + TreeItemDelegate( TreeView* parent = 0, TreeProxyModel* proxy = 0 ); protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -51,7 +51,7 @@ private slots: void doUpdateIndex( const QPersistentModelIndex& index ); private: - ArtistView* m_view; + TreeView* m_view; TreeProxyModel* m_model; mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_pixmaps; diff --git a/src/libtomahawk/playlist/ArtistView.cpp b/src/libtomahawk/playlist/TreeView.cpp similarity index 93% rename from src/libtomahawk/playlist/ArtistView.cpp rename to src/libtomahawk/playlist/TreeView.cpp index b62a9f16b..16820325e 100644 --- a/src/libtomahawk/playlist/ArtistView.cpp +++ b/src/libtomahawk/playlist/TreeView.cpp @@ -17,7 +17,7 @@ * along with Tomahawk. If not, see . */ -#include "ArtistView.h" +#include "TreeView.h" #include #include @@ -45,7 +45,7 @@ using namespace Tomahawk; -ArtistView::ArtistView( QWidget* parent ) +TreeView::TreeView( QWidget* parent ) : QTreeView( parent ) , m_header( new ViewHeader( this ) ) , m_overlay( new OverlayWidget( this ) ) @@ -98,14 +98,14 @@ ArtistView::ArtistView( QWidget* parent ) } -ArtistView::~ArtistView() +TreeView::~TreeView() { tDebug() << Q_FUNC_INFO; } void -ArtistView::setProxyModel( TreeProxyModel* model ) +TreeView::setProxyModel( TreeProxyModel* model ) { m_proxyModel = model; TreeItemDelegate* del = new TreeItemDelegate( this, m_proxyModel ); @@ -117,7 +117,7 @@ ArtistView::setProxyModel( TreeProxyModel* model ) void -ArtistView::setModel( QAbstractItemModel* model ) +TreeView::setModel( QAbstractItemModel* model ) { Q_UNUSED( model ); qDebug() << "Explicitly use setPlaylistModel instead"; @@ -126,7 +126,7 @@ ArtistView::setModel( QAbstractItemModel* model ) void -ArtistView::setTreeModel( TreeModel* model ) +TreeView::setTreeModel( TreeModel* model ) { m_model = model; @@ -169,7 +169,7 @@ ArtistView::setTreeModel( TreeModel* model ) void -ArtistView::onViewChanged() +TreeView::onViewChanged() { if ( m_timer.isActive() ) m_timer.stop(); @@ -179,7 +179,7 @@ ArtistView::onViewChanged() void -ArtistView::onScrollTimeout() +TreeView::onScrollTimeout() { if ( m_timer.isActive() ) m_timer.stop(); @@ -207,7 +207,7 @@ ArtistView::onScrollTimeout() void -ArtistView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) +TreeView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { QTreeView::currentChanged( current, previous ); @@ -230,7 +230,7 @@ ArtistView::currentChanged( const QModelIndex& current, const QModelIndex& previ void -ArtistView::onItemActivated( const QModelIndex& index ) +TreeView::onItemActivated( const QModelIndex& index ) { PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); if ( item ) @@ -249,7 +249,7 @@ ArtistView::onItemActivated( const QModelIndex& index ) void -ArtistView::keyPressEvent( QKeyEvent* event ) +TreeView::keyPressEvent( QKeyEvent* event ) { QTreeView::keyPressEvent( event ); @@ -264,7 +264,7 @@ ArtistView::keyPressEvent( QKeyEvent* event ) void -ArtistView::resizeEvent( QResizeEvent* event ) +TreeView::resizeEvent( QResizeEvent* event ) { QTreeView::resizeEvent( event ); m_header->checkState(); @@ -280,7 +280,7 @@ ArtistView::resizeEvent( QResizeEvent* event ) void -ArtistView::onItemCountChanged( unsigned int items ) +TreeView::onItemCountChanged( unsigned int items ) { if ( items == 0 ) { @@ -297,7 +297,7 @@ ArtistView::onItemCountChanged( unsigned int items ) void -ArtistView::onFilterChangeFinished() +TreeView::onFilterChangeFinished() { if ( selectedIndexes().count() ) scrollTo( selectedIndexes().at( 0 ), QAbstractItemView::PositionAtCenter ); @@ -314,7 +314,7 @@ ArtistView::onFilterChangeFinished() void -ArtistView::onFilteringStarted() +TreeView::onFilteringStarted() { m_overlay->hide(); m_loadingSpinner->fadeIn(); @@ -322,7 +322,7 @@ ArtistView::onFilteringStarted() void -ArtistView::startDrag( Qt::DropActions supportedActions ) +TreeView::startDrag( Qt::DropActions supportedActions ) { QList pindexes; QModelIndexList indexes; @@ -362,7 +362,7 @@ ArtistView::startDrag( Qt::DropActions supportedActions ) void -ArtistView::onCustomContextMenu( const QPoint& pos ) +TreeView::onCustomContextMenu( const QPoint& pos ) { m_contextMenu->clear(); @@ -403,7 +403,7 @@ ArtistView::onCustomContextMenu( const QPoint& pos ) void -ArtistView::onMenuTriggered( int action ) +TreeView::onMenuTriggered( int action ) { switch ( action ) { @@ -418,7 +418,7 @@ ArtistView::onMenuTriggered( int action ) bool -ArtistView::jumpToCurrentTrack() +TreeView::jumpToCurrentTrack() { if ( !m_proxyModel ) return false; @@ -429,7 +429,7 @@ ArtistView::jumpToCurrentTrack() QString -ArtistView::guid() const +TreeView::guid() const { if ( m_guid.isEmpty() ) { diff --git a/src/libtomahawk/playlist/ArtistView.h b/src/libtomahawk/playlist/TreeView.h similarity index 94% rename from src/libtomahawk/playlist/ArtistView.h rename to src/libtomahawk/playlist/TreeView.h index 47b01dc36..cee339518 100644 --- a/src/libtomahawk/playlist/ArtistView.h +++ b/src/libtomahawk/playlist/TreeView.h @@ -17,8 +17,8 @@ * along with Tomahawk. If not, see . */ -#ifndef ARTISTVIEW_H -#define ARTISTVIEW_H +#ifndef TREEVIEW_H +#define TREEVIEW_H #include #include @@ -41,13 +41,13 @@ class AnimatedSpinner; class OverlayWidget; class TreeModel; -class DLLEXPORT ArtistView : public QTreeView, public Tomahawk::ViewPage +class DLLEXPORT TreeView : public QTreeView, public Tomahawk::ViewPage { Q_OBJECT public: - explicit ArtistView( QWidget* parent = 0 ); - ~ArtistView(); + explicit TreeView( QWidget* parent = 0 ); + ~TreeView(); virtual QString guid() const; virtual void setGuid( const QString& guid ) { m_guid = guid; } @@ -122,4 +122,4 @@ private: mutable QString m_guid; }; -#endif // ARTISTVIEW_H +#endif // TREEVIEW_H diff --git a/src/libtomahawk/widgets/WhatsHotWidget.ui b/src/libtomahawk/widgets/WhatsHotWidget.ui index b684f1566..88eb41339 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.ui +++ b/src/libtomahawk/widgets/WhatsHotWidget.ui @@ -33,7 +33,7 @@ - + 320 @@ -69,9 +69,9 @@
    playlist/GridView.h
    - ArtistView + TreeView QTreeView -
    ArtistView.h
    +
    TreeView.h
    PlaylistView diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui index 61107dc20..ec146f484 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui @@ -22,7 +22,7 @@ 1 - + @@ -48,9 +48,9 @@
    widgets/HeaderLabel.h
    - ArtistView + TreeView QTreeView -
    ArtistView.h
    +
    TreeView.h
    GridView diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index e882b823b..246a3e593 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -108,11 +108,6 @@ QPushButton
    widgets/ToggleButton.h
    - - ArtistView - QTreeView -
    ArtistView.h
    -
    GridView QListView diff --git a/src/sourcetree/SourcesModel.cpp b/src/sourcetree/SourcesModel.cpp index 3a56eded8..2c383ef40 100644 --- a/src/sourcetree/SourcesModel.cpp +++ b/src/sourcetree/SourcesModel.cpp @@ -40,7 +40,7 @@ #include "GlobalActionManager.h" #include "DropJob.h" #include "items/PlaylistItems.h" -#include "playlist/ArtistView.h" +#include "playlist/TreeView.h" #include "playlist/PlaylistView.h" #include "playlist/dynamic/widgets/DynamicWidget.h" From 1d1b3ff3823cd332798a02cab5865ed46fdc185f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 06:35:15 +0200 Subject: [PATCH 229/433] * No need to manually disable OverlayWidget anymore. --- src/libtomahawk/widgets/WhatsHotWidget.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libtomahawk/widgets/WhatsHotWidget.cpp b/src/libtomahawk/widgets/WhatsHotWidget.cpp index dc3692ad1..2d2c8ddef 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.cpp +++ b/src/libtomahawk/widgets/WhatsHotWidget.cpp @@ -38,7 +38,6 @@ #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" -#include "widgets/OverlayWidget.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Pipeline.h" @@ -76,7 +75,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) connect( ui->breadCrumbLeft, SIGNAL( activateIndex( QModelIndex ) ), SLOT( leftCrumbIndexChanged(QModelIndex) ) ); - ui->tracksViewLeft->overlay()->setEnabled( false ); ui->tracksViewLeft->setHeaderHidden( true ); ui->tracksViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); PlaylistChartItemDelegate* del = new PlaylistChartItemDelegate( ui->tracksViewLeft, ui->tracksViewLeft->proxyModel() ); From 18183c512f16cc82c9b304dc43b79a4624553789 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 06:37:11 +0200 Subject: [PATCH 230/433] * No need to include OverlayWidget anymore. --- src/libtomahawk/widgets/NewReleasesWidget.cpp | 1 - src/libtomahawk/widgets/NewReleasesWidget.h | 1 - src/libtomahawk/widgets/WhatsHotWidget.h | 1 - 3 files changed, 3 deletions(-) diff --git a/src/libtomahawk/widgets/NewReleasesWidget.cpp b/src/libtomahawk/widgets/NewReleasesWidget.cpp index 6c91799c7..c4e7631bc 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.cpp +++ b/src/libtomahawk/widgets/NewReleasesWidget.cpp @@ -38,7 +38,6 @@ #include "playlist/PlaylistModel.h" #include "playlist/TreeProxyModel.h" #include "playlist/PlaylistChartItemDelegate.h" -#include "widgets/OverlayWidget.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" #include "Pipeline.h" diff --git a/src/libtomahawk/widgets/NewReleasesWidget.h b/src/libtomahawk/widgets/NewReleasesWidget.h index 333266852..5e6c21cf7 100644 --- a/src/libtomahawk/widgets/NewReleasesWidget.h +++ b/src/libtomahawk/widgets/NewReleasesWidget.h @@ -37,7 +37,6 @@ class QStandardItemModel; class QStandardItem; class TreeModel; class PlaylistModel; -class OverlayWidget; class TreeProxyModel; class AlbumModel; class PlayableModel; diff --git a/src/libtomahawk/widgets/WhatsHotWidget.h b/src/libtomahawk/widgets/WhatsHotWidget.h index 372ba0aa3..851b4c281 100644 --- a/src/libtomahawk/widgets/WhatsHotWidget.h +++ b/src/libtomahawk/widgets/WhatsHotWidget.h @@ -36,7 +36,6 @@ class QStandardItemModel; class QStandardItem; class TreeModel; class PlaylistModel; -class OverlayWidget; class TreeProxyModel; class PlayableModel; From 161b8603598c7710edb7064a1ef684c012307fac Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 06:39:24 +0200 Subject: [PATCH 231/433] * No need to manually disable or include OverlayWidget anymore. --- src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp | 3 --- src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h | 1 - src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp | 3 --- src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h | 1 - src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp | 4 ---- 5 files changed, 12 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 4b6b5a6eb..812e7dc04 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -34,9 +34,6 @@ #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "widgets/OverlayButton.h" -#include "widgets/OverlayWidget.h" - using namespace Tomahawk; diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h index 4234914ec..9d00c2847 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h @@ -41,7 +41,6 @@ class PlayableModel; class TreeModel; -class OverlayButton; namespace Ui { diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 64d84dfca..18e364e36 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -35,9 +35,6 @@ #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "widgets/OverlayButton.h" -#include "widgets/OverlayWidget.h" - #include "Pipeline.h" using namespace Tomahawk; diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index 9d3588ed0..17477da1a 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -41,7 +41,6 @@ class PlayableModel; class PlaylistModel; -class OverlayButton; namespace Ui { diff --git a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp index f1fa9b307..fb02f275a 100644 --- a/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/SourceInfoWidget.cpp @@ -32,8 +32,6 @@ #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "widgets/OverlayWidget.h" - SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* parent ) : QWidget( parent ) @@ -51,8 +49,6 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* ui->splitter->setStretchFactor( 0, 0 ); ui->splitter->setStretchFactor( 1, 1 ); - ui->historyView->overlay()->setEnabled( false ); - m_recentTracksModel = new RecentlyAddedModel( source, ui->recentCollectionView ); m_recentTracksModel->setStyle( PlayableModel::Short ); ui->recentCollectionView->setPlayableModel( m_recentTracksModel ); From 4a47f6dd22b11a9c559d478015de8f88dd01d193 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 06:41:57 +0200 Subject: [PATCH 232/433] * No need to manually disable or include OverlayWidget anymore. --- src/libtomahawk/playlist/QueueView.cpp | 2 -- src/libtomahawk/widgets/SearchWidget.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 885909229..a8414bfdc 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -23,7 +23,6 @@ #include "widgets/HeaderLabel.h" #include "playlist/QueueProxyModel.h" -#include "widgets/OverlayWidget.h" #include "utils/Logger.h" #include "PlaylistView.h" #include "Source.h" @@ -45,7 +44,6 @@ QueueView::QueueView( AnimatedSplitter* parent ) ui->queue->setProxyModel( new QueueProxyModel( ui->queue ) ); ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); - ui->queue->overlay()->setEnabled( false ); PlaylistModel* queueModel = new PlaylistModel( this ); queueModel->setStyle( PlaylistModel::Short ); diff --git a/src/libtomahawk/widgets/SearchWidget.cpp b/src/libtomahawk/widgets/SearchWidget.cpp index 047229cc3..81f794204 100644 --- a/src/libtomahawk/widgets/SearchWidget.cpp +++ b/src/libtomahawk/widgets/SearchWidget.cpp @@ -27,7 +27,6 @@ #include "ViewManager.h" #include "playlist/PlayableModel.h" #include "playlist/PlaylistModel.h" -#include "widgets/OverlayWidget.h" #include "utils/AnimatedSpinner.h" #include "utils/TomahawkUtilsGui.h" @@ -44,7 +43,6 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent ) ui->resultsView->setGuid( "searchwidget" ); m_resultsModel = new PlaylistModel( ui->resultsView ); ui->resultsView->setPlaylistModel( m_resultsModel ); - ui->resultsView->overlay()->setEnabled( false ); ui->resultsView->sortByColumn( PlaylistModel::Score, Qt::DescendingOrder ); m_albumsModel = new PlayableModel( ui->albumView ); From 4634f95b4c8d542e002131362290055eb29efade Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 06:47:02 +0200 Subject: [PATCH 233/433] * Temporarily work-around QSqliteDriver's race condition issues. --- src/libtomahawk/database/Database.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/database/Database.cpp b/src/libtomahawk/database/Database.cpp index 8ed84597f..8c7199092 100644 --- a/src/libtomahawk/database/Database.cpp +++ b/src/libtomahawk/database/Database.cpp @@ -26,7 +26,12 @@ #include "Source.h" #define DEFAULT_WORKER_THREADS 4 -#define MAX_WORKER_THREADS 16 + +#if ( QT_VERSION >= QT_VERSION_CHECK(4, 8, 2) ) + #define MAX_WORKER_THREADS 1 +#else + #define MAX_WORKER_THREADS 16 +#endif Database* Database::s_instance = 0; @@ -46,8 +51,12 @@ Database::Database( const QString& dbname, QObject* parent ) { s_instance = this; - m_maxConcurrentThreads = qBound( DEFAULT_WORKER_THREADS, QThread::idealThreadCount(), MAX_WORKER_THREADS ); - qDebug() << Q_FUNC_INFO << "Using" << m_maxConcurrentThreads << "threads"; + if ( MAX_WORKER_THREADS < DEFAULT_WORKER_THREADS ) + m_maxConcurrentThreads = MAX_WORKER_THREADS; + else + m_maxConcurrentThreads = qBound( DEFAULT_WORKER_THREADS, QThread::idealThreadCount(), MAX_WORKER_THREADS ); + + tDebug() << Q_FUNC_INFO << "Using" << m_maxConcurrentThreads << "database worker threads"; connect( m_impl, SIGNAL( indexReady() ), SIGNAL( indexReady() ) ); connect( m_impl, SIGNAL( indexReady() ), SIGNAL( ready() ) ); From 3a47a5f9c859c7df2a7a2e7cf47bbb062c4cf74b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 06:57:13 +0200 Subject: [PATCH 234/433] * Never show an empty OverlayWidget. --- src/libtomahawk/widgets/OverlayWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index 745245df5..a3cc273f2 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -131,7 +131,7 @@ void OverlayWidget::onViewChanged() { PlayableProxyModel* model = qobject_cast( m_parent->model() ); - if ( model && ( model->rowCount( QModelIndex() ) || model->isLoading() ) ) + if ( m_text.isEmpty() || ( model && ( model->rowCount( QModelIndex() ) || model->isLoading() ) ) ) { hide(); } From d713dec19d26844052ccce3813e9aead0688412c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:09:44 +0200 Subject: [PATCH 235/433] * OverlayWidget needs to update when items get removed, too. --- src/libtomahawk/widgets/OverlayWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index a3cc273f2..605907fd9 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -47,6 +47,7 @@ OverlayWidget::OverlayWidget( QAbstractItemView* parent ) if ( m_parent->model() ) { connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); } connect( m_parent, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); @@ -131,6 +132,7 @@ void OverlayWidget::onViewChanged() { PlayableProxyModel* model = qobject_cast( m_parent->model() ); + if ( m_text.isEmpty() || ( model && ( model->rowCount( QModelIndex() ) || model->isLoading() ) ) ) { hide(); From 0a7b6c9a22c5d2365de9ebc43a04cacf3408e121 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:10:27 +0200 Subject: [PATCH 236/433] * Make start- / finishLoading public methods of PlayableModel. --- src/libtomahawk/playlist/PlayableModel.cpp | 4 ++-- src/libtomahawk/playlist/PlayableModel.h | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index b6c7347a2..e3b5817cd 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -37,12 +37,12 @@ using namespace Tomahawk; -PlayableModel::PlayableModel( QObject* parent ) +PlayableModel::PlayableModel( QObject* parent, bool loading ) : QAbstractItemModel( parent ) , m_rootItem( new PlayableItem( 0, this ) ) , m_readOnly( true ) , m_style( Detailed ) - , m_loading( true ) + , m_loading( loading ) { connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection ); diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 4a219dee6..2d436c5db 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -60,7 +60,7 @@ public: Name = 12 }; - explicit PlayableModel( QObject* parent = 0 ); + explicit PlayableModel( QObject* parent = 0, bool loading = true ); virtual ~PlayableModel(); PlayableModel::PlayableItemStyle style() const { return m_style; } @@ -117,6 +117,9 @@ public: void setItemSize( const QSize& size ) { m_itemSize = size; } + void startLoading(); + void finishLoading(); + signals: void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode ); void shuffleModeChanged( bool enabled ); @@ -156,8 +159,6 @@ public slots: protected: PlayableItem* rootItem() const { return m_rootItem; } - void startLoading(); - void finishLoading(); private slots: void onDataChanged(); From 218098e1ff0bc0d5c1ced4522ddc2de1e740767b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:11:02 +0200 Subject: [PATCH 237/433] * Allow API users to set an empty tooltip for TrackViews. --- src/libtomahawk/playlist/TrackView.cpp | 7 +++++++ src/libtomahawk/playlist/TrackView.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index 5eb8991f3..e9d220d99 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -173,6 +173,13 @@ TrackView::setPlayableModel( PlayableModel* model ) } +void +TrackView::setEmptyTip( const QString& tip ) +{ + m_overlay->setText( tip ); +} + + void TrackView::onViewChanged() { diff --git a/src/libtomahawk/playlist/TrackView.h b/src/libtomahawk/playlist/TrackView.h index cab45742d..873e2037a 100644 --- a/src/libtomahawk/playlist/TrackView.h +++ b/src/libtomahawk/playlist/TrackView.h @@ -60,6 +60,8 @@ public: Tomahawk::ContextMenu* contextMenu() const { return m_contextMenu; } AnimatedSpinner* loadingSpinner() const { return m_loadingSpinner; } + void setEmptyTip( const QString& tip ); + virtual QWidget* widget() { return this; } virtual Tomahawk::playlistinterface_ptr playlistInterface() const; From 27e7186b9883e38e03d69d66b4870597bfad9955 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:11:28 +0200 Subject: [PATCH 238/433] * Set an empty-tooltip for the QueueView. --- src/libtomahawk/playlist/QueueView.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index a8414bfdc..1012b9610 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -42,6 +42,7 @@ QueueView::QueueView( AnimatedSplitter* parent ) setHiddenSize( QSize( 0, 22 ) ); + ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); ui->queue->setProxyModel( new QueueProxyModel( ui->queue ) ); ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); @@ -49,6 +50,7 @@ QueueView::QueueView( AnimatedSplitter* parent ) queueModel->setStyle( PlaylistModel::Short ); ui->queue->setPlaylistModel( queueModel ); queueModel->setReadOnly( false ); + queueModel->finishLoading(); connect( queueModel, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( updateLabel() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); From 0d63fb97f7365c61602d39c66a7ec6e68988c800 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:13:56 +0200 Subject: [PATCH 239/433] * Set proper defautl empty-tooltips for PlaylistViews. --- src/libtomahawk/playlist/PlaylistView.cpp | 20 +++++--------------- src/libtomahawk/playlist/PlaylistView.h | 1 - 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index e6a2e4675..b8292b29b 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -22,7 +22,6 @@ #include #include -#include "widgets/OverlayWidget.h" #include "ViewManager.h" #include "utils/Logger.h" #include "PlaylistUpdaterInterface.h" @@ -75,7 +74,11 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) } } - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) ); + if ( model->isReadOnly() ) + setEmptyTip( tr( "This playlist is currently empty." ) ); + else + setEmptyTip( tr( "This playlist is currently empty. Add some tracks to it and enjoy the music!" ) ); + connect( m_model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) ); connect( m_model, SIGNAL( playlistChanged() ), SLOT( onChanged() ) ); @@ -117,19 +120,6 @@ PlaylistView::updaters() const } -void -PlaylistView::onTrackCountChanged( unsigned int tracks ) -{ - if ( tracks == 0 ) - { - overlay()->setText( tr( "This playlist is currently empty. Add some tracks to it and enjoy the music!" ) ); - overlay()->show(); - } - else - overlay()->hide(); -} - - void PlaylistView::onDeleted() { diff --git a/src/libtomahawk/playlist/PlaylistView.h b/src/libtomahawk/playlist/PlaylistView.h index e3cbbcf53..48d7c6892 100644 --- a/src/libtomahawk/playlist/PlaylistView.h +++ b/src/libtomahawk/playlist/PlaylistView.h @@ -52,7 +52,6 @@ protected: void keyPressEvent( QKeyEvent* event ); private slots: - void onTrackCountChanged( unsigned int tracks ); void onMenuTriggered( int action ); void deleteItems(); From 669537263921fb9ee09804b4cb037c25a57046ef Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:45:58 +0200 Subject: [PATCH 240/433] * Auto resize OverlayWidget to a reasonable size. --- src/libtomahawk/widgets/OverlayWidget.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index 605907fd9..d8801a11d 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -36,7 +36,6 @@ OverlayWidget::OverlayWidget( QAbstractItemView* parent ) , m_opacity( 0.00 ) , m_parent( parent ) { - resize( 380, 128 ); setAttribute( Qt::WA_TranslucentBackground, true ); setOpacity( m_opacity ); @@ -86,6 +85,7 @@ void OverlayWidget::setText( const QString& text ) { m_text = text; + onViewChanged(); } @@ -150,6 +150,7 @@ OverlayWidget::onViewModelChanged() if ( m_parent->model() ) { connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); onViewChanged(); } } @@ -160,6 +161,17 @@ OverlayWidget::paintEvent( QPaintEvent* event ) { Q_UNUSED( event ); + { + QSize maxiSize = QSize( (double)m_parent->viewport()->width() * 0.70, (double)m_parent->viewport()->height() * 0.70 ); + QSize prefSize = QSize( 380, 128 ); + int width = qMin( maxiSize.width(), prefSize.width() ); + int height = qMin( maxiSize.height(), prefSize.height() ); + QSize newSize = QSize( width, height ); + + if ( newSize != size() ) + resize( newSize ); + } + QPoint center( ( m_parent->width() - width() ) / 2, ( m_parent->height() - height() ) / 2 ); if ( center != pos() ) { From 83e073fc7c441f2620ee38b179f060ba20f5139a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:46:28 +0200 Subject: [PATCH 241/433] * AnimatedWidget emits a signal when the sliding animation is done. --- src/libtomahawk/widgets/AnimatedSplitter.cpp | 2 ++ src/libtomahawk/widgets/AnimatedSplitter.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libtomahawk/widgets/AnimatedSplitter.cpp b/src/libtomahawk/widgets/AnimatedSplitter.cpp index 26a483266..539433136 100644 --- a/src/libtomahawk/widgets/AnimatedSplitter.cpp +++ b/src/libtomahawk/widgets/AnimatedSplitter.cpp @@ -277,6 +277,8 @@ AnimatedWidget::onAnimationFinished() { setFixedHeight( hiddenSize().height() ); } + + emit animationFinished(); } diff --git a/src/libtomahawk/widgets/AnimatedSplitter.h b/src/libtomahawk/widgets/AnimatedSplitter.h index a8ef35325..d113e769e 100644 --- a/src/libtomahawk/widgets/AnimatedSplitter.h +++ b/src/libtomahawk/widgets/AnimatedSplitter.h @@ -104,6 +104,8 @@ public slots: signals: void showWidget(); void hideWidget(); + + void animationFinished(); void resizeBy( const QPoint& delta ); void sizeChanged( const QSize& size ); From 1da5ea8ae7d3382606fbc4904fc55cf570a2a2c1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:46:59 +0200 Subject: [PATCH 242/433] * Show / hide the empty-tooltip when sliding. --- src/libtomahawk/playlist/QueueView.cpp | 16 ++++++++++++++-- src/libtomahawk/playlist/QueueView.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 1012b9610..83c1414ba 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -27,6 +27,7 @@ #include "PlaylistView.h" #include "Source.h" #include "utils/TomahawkUtilsGui.h" +#include "widgets/OverlayWidget.h" using namespace Tomahawk; @@ -42,18 +43,20 @@ QueueView::QueueView( AnimatedSplitter* parent ) setHiddenSize( QSize( 0, 22 ) ); - ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); ui->queue->setProxyModel( new QueueProxyModel( ui->queue ) ); ui->queue->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); PlaylistModel* queueModel = new PlaylistModel( this ); queueModel->setStyle( PlaylistModel::Short ); + queueModel->finishLoading(); ui->queue->setPlaylistModel( queueModel ); queueModel->setReadOnly( false ); - queueModel->finishLoading(); + + ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); connect( queueModel, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( updateLabel() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); + connect( this, SIGNAL( animationFinished() ), SLOT( onAnimationFinished() ) ); ui->toggleButton->installEventFilter( this ); ui->toggleButton->setCursor( Qt::PointingHandCursor ); @@ -125,6 +128,7 @@ QueueView::hide() connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); disconnect( ui->toggleButton, SIGNAL( resized( QPoint ) ), this, SIGNAL( resizeBy( QPoint ) ) ); + ui->queue->overlay()->setVisible( false ); AnimatedWidget::hide(); updateLabel(); } @@ -137,6 +141,7 @@ QueueView::show() connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( hide() ) ); connect( ui->toggleButton, SIGNAL( resized( QPoint ) ), SIGNAL( resizeBy( QPoint ) ) ); + ui->queue->overlay()->setVisible( false ); AnimatedWidget::show(); updateLabel(); } @@ -162,6 +167,13 @@ QueueView::onHidden( QWidget* widget, bool animated ) } +void +QueueView::onAnimationFinished() +{ + ui->queue->overlay()->setVisible( true ); +} + + void QueueView::updateLabel() { diff --git a/src/libtomahawk/playlist/QueueView.h b/src/libtomahawk/playlist/QueueView.h index 9500264f0..ce8ef7eae 100644 --- a/src/libtomahawk/playlist/QueueView.h +++ b/src/libtomahawk/playlist/QueueView.h @@ -59,6 +59,7 @@ protected: private slots: void updateLabel(); + void onAnimationFinished(); private: Ui::QueueView* ui; From 5ee92afb366b7a59b0493f676545e8d8395fc43d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:48:50 +0200 Subject: [PATCH 243/433] * Restore the empty-tooltip when filtering is done. --- src/libtomahawk/playlist/TrackView.cpp | 10 ++++++++++ src/libtomahawk/playlist/TrackView.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/TrackView.cpp b/src/libtomahawk/playlist/TrackView.cpp index e9d220d99..418d92827 100644 --- a/src/libtomahawk/playlist/TrackView.cpp +++ b/src/libtomahawk/playlist/TrackView.cpp @@ -176,6 +176,7 @@ TrackView::setPlayableModel( PlayableModel* model ) void TrackView::setEmptyTip( const QString& tip ) { + m_emptyTip = tip; m_overlay->setText( tip ); } @@ -508,8 +509,17 @@ TrackView::onFilterChanged( const QString& ) m_overlay->show(); } else + { if ( model()->trackCount() ) + { m_overlay->hide(); + } + else + { + m_overlay->setText( m_emptyTip ); + m_overlay->show(); + } + } } diff --git a/src/libtomahawk/playlist/TrackView.h b/src/libtomahawk/playlist/TrackView.h index 873e2037a..24f119a7e 100644 --- a/src/libtomahawk/playlist/TrackView.h +++ b/src/libtomahawk/playlist/TrackView.h @@ -137,6 +137,7 @@ private: OverlayWidget* m_overlay; AnimatedSpinner* m_loadingSpinner; + QString m_emptyTip; bool m_resizing; bool m_dragging; QRect m_dropRect; @@ -147,7 +148,6 @@ private: QModelIndex m_contextMenuIndex; Tomahawk::query_ptr m_autoPlaying; - Tomahawk::ContextMenu* m_contextMenu; QTimer m_timer; From 137fce34454d7a98789afe83c9a1c510d03b6b70 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 07:49:06 +0200 Subject: [PATCH 244/433] * Remove debug in PlaylistView. --- src/libtomahawk/playlist/PlaylistView.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index b8292b29b..46971b060 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -89,7 +89,6 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) void PlaylistView::keyPressEvent( QKeyEvent* event ) { - qDebug() << Q_FUNC_INFO; TrackView::keyPressEvent( event ); if ( !model() ) From 43c1c498d6470efb04dfb5b9e6a1feaa56478af8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:09:07 +0200 Subject: [PATCH 245/433] * Also hook up OverlayWidget with the model's loading signals. --- src/libtomahawk/widgets/OverlayWidget.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index d8801a11d..4917c84cf 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -47,6 +47,8 @@ OverlayWidget::OverlayWidget( QAbstractItemView* parent ) { connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); connect( m_parent->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); } connect( m_parent, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); @@ -151,6 +153,9 @@ OverlayWidget::onViewModelChanged() { connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); connect( m_parent->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + onViewChanged(); } } From 2aa71d130f9f8d801b5e766d97fc77e292da3a26 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:09:35 +0200 Subject: [PATCH 246/433] * Properly set empty tooltip for PlaylistModels/Views. --- src/libtomahawk/playlist/PlaylistModel.cpp | 3 +-- src/libtomahawk/playlist/PlaylistView.cpp | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistModel.cpp b/src/libtomahawk/playlist/PlaylistModel.cpp index 5ed5241bb..78b27d8fd 100644 --- a/src/libtomahawk/playlist/PlaylistModel.cpp +++ b/src/libtomahawk/playlist/PlaylistModel.cpp @@ -84,6 +84,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn .arg( TomahawkUtils::ageToString( QDateTime::fromTime_t( playlist->createdOn() ), true ) ) ); m_isTemporary = false; + emit playlistChanged(); if ( !loadEntries ) { @@ -92,8 +93,6 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn } QList entries = playlist->entries(); - - qDebug() << "playlist loading entries:"; foreach( const plentry_ptr& p, entries ) qDebug() << p->guid() << p->query()->track() << p->query()->artist(); diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index 46971b060..2d43879fa 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -62,6 +62,8 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) setColumnHidden( PlayableModel::Age, true ); // Hide age column per default setColumnHidden( PlayableModel::Composer, true ); // Hide composer column per default + onChanged(); + if ( guid().isEmpty() ) { if ( !m_model->playlist().isNull() ) @@ -74,11 +76,6 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) } } - if ( model->isReadOnly() ) - setEmptyTip( tr( "This playlist is currently empty." ) ); - else - setEmptyTip( tr( "This playlist is currently empty. Add some tracks to it and enjoy the music!" ) ); - connect( m_model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) ); connect( m_model, SIGNAL( playlistChanged() ), SLOT( onChanged() ) ); @@ -130,9 +127,17 @@ PlaylistView::onDeleted() void PlaylistView::onChanged() { - if ( m_model && !m_model->playlist().isNull() && - ViewManager::instance()->currentPage() == this ) - emit nameChanged( m_model->playlist()->title() ); + if ( m_model ) + { + if ( m_model->isReadOnly() ) + setEmptyTip( tr( "This playlist is currently empty." ) ); + else + setEmptyTip( tr( "This playlist is currently empty. Add some tracks to it and enjoy the music!" ) ); + m_model->finishLoading(); + + if ( !m_model->playlist().isNull() && ViewManager::instance()->currentPage() == this ) + emit nameChanged( m_model->playlist()->title() ); + } } From 11e1a410e8b0188238ca97a9f55d1b1d1a1c08b3 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:43:27 +0200 Subject: [PATCH 247/433] * Let GridView manage empty-tooltips, too. --- src/libtomahawk/playlist/GridView.cpp | 9 ++++++++- src/libtomahawk/playlist/GridView.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/GridView.cpp b/src/libtomahawk/playlist/GridView.cpp index 7615e0edc..62209e3d5 100644 --- a/src/libtomahawk/playlist/GridView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -78,7 +78,6 @@ GridView::GridView( QWidget* parent ) /* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); m_overlay->setText( tr( "This collection doesn't have any recent albums." ) );*/ - m_overlay->setText( tr( "Nothing found." ) ); connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); @@ -133,6 +132,14 @@ GridView::setPlayableModel( PlayableModel* model ) } +void +GridView::setEmptyTip( const QString& tip ) +{ + m_emptyTip = tip; + m_overlay->setText( tip ); +} + + void GridView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { diff --git a/src/libtomahawk/playlist/GridView.h b/src/libtomahawk/playlist/GridView.h index f6ceb19e3..a69120969 100644 --- a/src/libtomahawk/playlist/GridView.h +++ b/src/libtomahawk/playlist/GridView.h @@ -57,6 +57,8 @@ public: void setPlayableModel( PlayableModel* model ); void setModel( QAbstractItemModel* model ); + void setEmptyTip( const QString& tip ); + virtual QWidget* widget() { return this; } virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } @@ -100,6 +102,7 @@ private: QModelIndex m_contextMenuIndex; Tomahawk::ContextMenu* m_contextMenu; + QString m_emptyTip; bool m_inited; bool m_autoFitItems; From 494df4e9a0289d718b5e7cf9fd6d815f5f744ebd Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:43:58 +0200 Subject: [PATCH 248/433] * Emit finishedLoading() when we start adding tracks to the model. --- src/libtomahawk/playlist/PlayableModel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index e3b5817cd..d068fde54 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -598,6 +598,8 @@ PlayableModel::insertInternal( const QList< T >& items, int row ) { emit trackCountChanged( rowCount( QModelIndex() ) ); emit itemCountChanged( rowCount( QModelIndex() ) ); + + finishLoading(); return; } @@ -624,6 +626,7 @@ PlayableModel::insertInternal( const QList< T >& items, int row ) emit endInsertRows(); emit trackCountChanged( rowCount( QModelIndex() ) ); + finishLoading(); } From 8ca0cfa917e90056813211f835026698ff09c01e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:44:11 +0200 Subject: [PATCH 249/433] * Emit finishedLoading() when we start adding tracks to the model. --- src/libtomahawk/playlist/PlaylistModel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/playlist/PlaylistModel.cpp b/src/libtomahawk/playlist/PlaylistModel.cpp index 78b27d8fd..7eae940c9 100644 --- a/src/libtomahawk/playlist/PlaylistModel.cpp +++ b/src/libtomahawk/playlist/PlaylistModel.cpp @@ -210,6 +210,7 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row ) if ( !entries.count() ) { emit trackCountChanged( rowCount( QModelIndex() ) ); + finishLoading(); return; } @@ -256,6 +257,7 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row ) emit endInsertRows(); emit trackCountChanged( rowCount( QModelIndex() ) ); + finishLoading(); } From 3928a2d0846397bd10b96fe4a7d10fb4da4470a5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:44:37 +0200 Subject: [PATCH 250/433] * Emit startLoading() when we start loading the playback history. --- src/libtomahawk/playlist/RecentlyPlayedModel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp index a61c92431..5902ee44a 100644 --- a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp +++ b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp @@ -68,6 +68,7 @@ RecentlyPlayedModel::loadHistory() { clear(); } + loadingStarted(); DatabaseCommand_PlaybackHistory* cmd = new DatabaseCommand_PlaybackHistory( m_source ); cmd->setLimit( m_limit ); From ba7556b0785f70329017c44e8a8a978b71d7d90b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:45:00 +0200 Subject: [PATCH 251/433] * Emit loading signals for CustomPlaylistViews. --- src/libtomahawk/playlist/CustomPlaylistView.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/playlist/CustomPlaylistView.cpp b/src/libtomahawk/playlist/CustomPlaylistView.cpp index 388dceea6..40f81ffdc 100644 --- a/src/libtomahawk/playlist/CustomPlaylistView.cpp +++ b/src/libtomahawk/playlist/CustomPlaylistView.cpp @@ -73,6 +73,8 @@ CustomPlaylistView::jumpToCurrentTrack() void CustomPlaylistView::generateTracks() { + m_model->startLoading(); + QString sql; switch ( m_type ) { @@ -105,6 +107,7 @@ CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks ) bool changed = false; QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks, changed ); + m_model->finishLoading(); if ( !changed ) return; From eff7669dd2ea920dec1e8d71fbf65c7c697d6014 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:45:20 +0200 Subject: [PATCH 252/433] * Always emit a playback history list, even if it's empty. --- src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp b/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp index 1aa3e37c8..a2093dd25 100644 --- a/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp +++ b/src/libtomahawk/database/DatabaseCommand_PlaybackHistory.cpp @@ -80,6 +80,5 @@ DatabaseCommand_PlaybackHistory::exec( DatabaseImpl* dbi ) } } - if ( ql.count() ) - emit tracks( ql ); + emit tracks( ql ); } From efc8616a178748c0f797b9538b4baba985864634 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:45:38 +0200 Subject: [PATCH 253/433] * onChanged() will be triggered automatically. --- src/libtomahawk/playlist/PlaylistView.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index 2d43879fa..5c8527754 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -62,8 +62,6 @@ PlaylistView::setPlaylistModel( PlaylistModel* model ) setColumnHidden( PlayableModel::Age, true ); // Hide age column per default setColumnHidden( PlayableModel::Composer, true ); // Hide composer column per default - onChanged(); - if ( guid().isEmpty() ) { if ( !m_model->playlist().isNull() ) From ba82de45b5244a0e834f38a9dae755d0bd9547af Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:46:13 +0200 Subject: [PATCH 254/433] * Only append similar tracks when we received some. --- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 98635bc59..893642628 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -86,6 +86,7 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par m_relatedTracksModel = new PlayableModel( ui->similarTracksView ); ui->similarTracksView->setPlayableModel( m_relatedTracksModel ); ui->similarTracksView->proxyModel()->sort( -1 ); + ui->similarTracksView->setEmptyTip( tr( "Sorry, but we could not find similar tracks for this song!" ) ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); @@ -154,7 +155,9 @@ TrackInfoWidget::load( const query_ptr& query ) ui->fromLabel->setVisible( !query->album().isEmpty() ); m_relatedTracksModel->clear(); - onSimilarTracksLoaded(); + + if ( !m_query->similarTracks().isEmpty() ) + onSimilarTracksLoaded(); } From 4efafaede10b46a83fcfeaa05b7c6e04074179fd Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 08:46:51 +0200 Subject: [PATCH 255/433] * Set empty-tooltips for Loved-, Recent Additions- and Recent Plays views. --- src/sourcetree/items/SourceItem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sourcetree/items/SourceItem.cpp b/src/sourcetree/items/SourceItem.cpp index 93f895d41..b495f4f23 100644 --- a/src/sourcetree/items/SourceItem.cpp +++ b/src/sourcetree/items/SourceItem.cpp @@ -506,6 +506,7 @@ SourceItem::lovedTracksClicked() PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() ); connect( del, SIGNAL( updateIndex( QModelIndex ) ), view, SLOT( update( QModelIndex ) ) ); view->setItemDelegate( del ); + view->setEmptyTip( tr( "Sorry, we could not find any loved tracks!" ) ); m_lovedTracksPage = view; } @@ -546,6 +547,7 @@ SourceItem::latestAdditionsClicked() cv->setPlayableModel( raModel ); cv->sortByColumn( PlayableModel::Age, Qt::DescendingOrder ); + cv->setEmptyTip( tr( "Sorry, we could not find any recent additions!" ) ); m_latestAdditionsPage = cv; } @@ -585,6 +587,7 @@ SourceItem::recentPlaysClicked() pv->setItemDelegate( del ); pv->setPlaylistModel( raModel ); + pv->setEmptyTip( tr( "Sorry, we could not find any recent plays!" ) ); m_recentPlaysPage = pv; } From 707c2a93d0f9a8ffe9a218629fcb195104c2cc9a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 09:04:21 +0200 Subject: [PATCH 256/433] * Let TreeView manage empty-tooltips, too. --- src/libtomahawk/playlist/TreeView.cpp | 8 ++++++++ src/libtomahawk/playlist/TreeView.h | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/TreeView.cpp b/src/libtomahawk/playlist/TreeView.cpp index 16820325e..31299e766 100644 --- a/src/libtomahawk/playlist/TreeView.cpp +++ b/src/libtomahawk/playlist/TreeView.cpp @@ -168,6 +168,14 @@ TreeView::setTreeModel( TreeModel* model ) } +void +TreeView::setEmptyTip( const QString& tip ) +{ + m_emptyTip = tip; + m_overlay->setText( tip ); +} + + void TreeView::onViewChanged() { diff --git a/src/libtomahawk/playlist/TreeView.h b/src/libtomahawk/playlist/TreeView.h index cee339518..254403c81 100644 --- a/src/libtomahawk/playlist/TreeView.h +++ b/src/libtomahawk/playlist/TreeView.h @@ -57,11 +57,12 @@ public: TreeModel* model() const { return m_model; } TreeProxyModel* proxyModel() const { return m_proxyModel; } OverlayWidget* overlay() const { return m_overlay; } - // PlaylistItemDelegate* delegate() { return m_delegate; } void setModel( QAbstractItemModel* model ); void setTreeModel( TreeModel* model ); + void setEmptyTip( const QString& tip ); + virtual QWidget* widget() { return this; } virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return proxyModel()->playlistInterface(); } @@ -117,6 +118,7 @@ private: QModelIndex m_contextMenuIndex; Tomahawk::ContextMenu* m_contextMenu; + QString m_emptyTip; bool m_showModes; QTimer m_timer; mutable QString m_guid; From 393d3370d3fa0ed1e514e85e4c0288df6f258cd1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 09:05:30 +0200 Subject: [PATCH 257/433] * Set empty-tooltips for Artist-,Album- and TrackInfoWidgets. --- src/libtomahawk/playlist/TreeModel.cpp | 3 ++- .../widgets/infowidgets/AlbumInfoWidget.cpp | 5 ++++- .../widgets/infowidgets/ArtistInfoWidget.cpp | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/playlist/TreeModel.cpp b/src/libtomahawk/playlist/TreeModel.cpp index 5b54db35a..9e9e57349 100644 --- a/src/libtomahawk/playlist/TreeModel.cpp +++ b/src/libtomahawk/playlist/TreeModel.cpp @@ -237,7 +237,8 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent, bool au connect( album.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), SLOT( onTracksFound( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) ); - onTracksAdded( album->tracks( m_mode, m_collection ), parent ); + if ( !album->tracks( m_mode, m_collection ).isEmpty() ) + onTracksAdded( album->tracks( m_mode, m_collection ), parent ); } diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 812e7dc04..3dc71d192 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -49,11 +49,13 @@ AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* par m_albumsModel = new PlayableModel( ui->albumsView ); ui->albumsView->setPlayableModel( m_albumsModel ); + ui->albumsView->setEmptyTip( tr( "Sorry, we could not find any other albums for this artist!" ) ); m_tracksModel = new TreeModel( ui->tracksView ); m_tracksModel->setMode( Mixed ); ui->tracksView->setTreeModel( m_tracksModel ); ui->tracksView->setRootIsDecorated( false ); + ui->tracksView->setEmptyTip( tr( "Sorry, we could not find any tracks for this album!" ) ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); @@ -154,7 +156,8 @@ AlbumInfoWidget::loadAlbums( bool autoRefetch ) connect( m_album->artist().data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), SLOT( gotAlbums( QList ) ) ); - gotAlbums( m_album->artist()->albums( Mixed ) ); + if ( !m_album->artist()->albums( Mixed ).isEmpty() ) + gotAlbums( m_album->artist()->albums( Mixed ) ); /* tDebug() << "Auto refetching"; m_buttonAlbums->setChecked( false ); diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 18e364e36..fe4edaa9d 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -58,15 +58,18 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* m_albumsModel = new PlayableModel( ui->albums ); ui->albums->setPlayableModel( m_albumsModel ); + ui->topHits->setEmptyTip( tr( "Sorry, we could not find any albums for this artist!" ) ); m_relatedModel = new PlayableModel( ui->relatedArtists ); ui->relatedArtists->setPlayableModel( m_relatedModel ); ui->relatedArtists->proxyModel()->sort( -1 ); + ui->topHits->setEmptyTip( tr( "Sorry, we could not find any related artists!" ) ); m_topHitsModel = new PlaylistModel( ui->topHits ); m_topHitsModel->setStyle( PlayableModel::Short ); ui->topHits->setPlayableModel( m_topHitsModel ); ui->topHits->setSortingEnabled( false ); + ui->topHits->setEmptyTip( tr( "Sorry, we could not find any top hits for this artist!" ) ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); @@ -161,9 +164,15 @@ ArtistInfoWidget::load( const artist_ptr& artist ) connect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), SLOT( onTracksFound( QList, Tomahawk::ModelMode ) ) ); - onAlbumsFound( artist->albums( Mixed ), Mixed ); - onTracksFound( m_artist->tracks(), Mixed ); - onSimilarArtistsLoaded(); + if ( !m_artist->albums( Mixed ).isEmpty() ) + onAlbumsFound( m_artist->albums( Mixed ), Mixed ); + + if ( !m_artist->tracks().isEmpty() ) + onTracksFound( m_artist->tracks(), Mixed ); + + if ( !m_artist->similarArtists().isEmpty() ) + onSimilarArtistsLoaded(); + onArtistImageUpdated(); Tomahawk::InfoSystem::InfoStringHash artistInfo; From a3545712ca38715bd0bd3fe5d22d40a4c58df27f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 09:38:54 +0200 Subject: [PATCH 258/433] * Show a empty-tooltip for collection views. --- src/libtomahawk/ViewManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 35c5970d5..445eea592 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -305,6 +305,11 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) view = new TreeView(); TreeModel* model = new TreeModel(); view->setTreeModel( model ); + + if ( collection && collection->source()->isLocal() ) + view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) ); + else + view->setEmptyTip( tr( "This collection is empty." ) ); model->addCollection( collection ); From 72c6b009ff91ca63af193cbdada846aa5b754ee2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 09:39:22 +0200 Subject: [PATCH 259/433] * Fixed resetting empty-tooltip in TreeView. --- src/libtomahawk/playlist/TreeView.cpp | 27 +++++++++------------------ src/libtomahawk/playlist/TreeView.h | 1 - 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/libtomahawk/playlist/TreeView.cpp b/src/libtomahawk/playlist/TreeView.cpp index 31299e766..ae6580f13 100644 --- a/src/libtomahawk/playlist/TreeView.cpp +++ b/src/libtomahawk/playlist/TreeView.cpp @@ -139,7 +139,6 @@ TreeView::setTreeModel( TreeModel* model ) connect( m_proxyModel, SIGNAL( filteringStarted() ), SLOT( onFilteringStarted() ) ); connect( m_proxyModel, SIGNAL( filteringFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); - connect( m_model, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemCountChanged( unsigned int ) ) ); connect( m_proxyModel, SIGNAL( filteringFinished() ), SLOT( onFilterChangeFinished() ) ); connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); @@ -287,23 +286,6 @@ TreeView::resizeEvent( QResizeEvent* event ) } -void -TreeView::onItemCountChanged( unsigned int items ) -{ - if ( items == 0 ) - { - if ( m_model->collection().isNull() || ( !m_model->collection().isNull() && m_model->collection()->source()->isLocal() ) ) - m_overlay->setText( tr( "After you have scanned your music collection you will find your tracks right here." ) ); - else - m_overlay->setText( tr( "This collection is currently empty." ) ); - - m_overlay->show(); - } - else - m_overlay->hide(); -} - - void TreeView::onFilterChangeFinished() { @@ -316,8 +298,17 @@ TreeView::onFilterChangeFinished() m_overlay->show(); } else + { if ( model()->trackCount() ) + { m_overlay->hide(); + } + else + { + m_overlay->setText( m_emptyTip ); + m_overlay->show(); + } + } } diff --git a/src/libtomahawk/playlist/TreeView.h b/src/libtomahawk/playlist/TreeView.h index 254403c81..8bd34cb03 100644 --- a/src/libtomahawk/playlist/TreeView.h +++ b/src/libtomahawk/playlist/TreeView.h @@ -97,7 +97,6 @@ protected slots: virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous ); private slots: - void onItemCountChanged( unsigned int items ); void onFilterChangeFinished(); void onFilteringStarted(); void onViewChanged(); From c1885fa6d93d1073a32edbae98153ed06dcf5b75 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 10:26:22 +0200 Subject: [PATCH 260/433] * Support AIFF type audio files. --- src/MusicScanner.cpp | 43 +++++++++++++------------ src/libtomahawk/taghandlers/tag.cpp | 7 ++++ src/libtomahawk/utils/TomahawkUtils.cpp | 4 ++- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/MusicScanner.cpp b/src/MusicScanner.cpp index f7e30c5e0..f1b489878 100644 --- a/src/MusicScanner.cpp +++ b/src/MusicScanner.cpp @@ -106,15 +106,17 @@ MusicScanner::MusicScanner( const QStringList& dirs, quint32 bs ) , m_batchsize( bs ) , m_dirListerThreadController( 0 ) { - m_ext2mime.insert( "mp3", TomahawkUtils::extensionToMimetype( "mp3" ) ); - m_ext2mime.insert( "ogg", TomahawkUtils::extensionToMimetype( "ogg" ) ); - m_ext2mime.insert( "oga", TomahawkUtils::extensionToMimetype( "oga" ) ); - m_ext2mime.insert( "mpc", TomahawkUtils::extensionToMimetype( "mpc" ) ); - m_ext2mime.insert( "wma", TomahawkUtils::extensionToMimetype( "wma" ) ); - m_ext2mime.insert( "aac", TomahawkUtils::extensionToMimetype( "aac" ) ); - m_ext2mime.insert( "m4a", TomahawkUtils::extensionToMimetype( "m4a" ) ); - m_ext2mime.insert( "mp4", TomahawkUtils::extensionToMimetype( "mp4" ) ); + m_ext2mime.insert( "mp3", TomahawkUtils::extensionToMimetype( "mp3" ) ); + m_ext2mime.insert( "ogg", TomahawkUtils::extensionToMimetype( "ogg" ) ); + m_ext2mime.insert( "oga", TomahawkUtils::extensionToMimetype( "oga" ) ); + m_ext2mime.insert( "mpc", TomahawkUtils::extensionToMimetype( "mpc" ) ); + m_ext2mime.insert( "wma", TomahawkUtils::extensionToMimetype( "wma" ) ); + m_ext2mime.insert( "aac", TomahawkUtils::extensionToMimetype( "aac" ) ); + m_ext2mime.insert( "m4a", TomahawkUtils::extensionToMimetype( "m4a" ) ); + m_ext2mime.insert( "mp4", TomahawkUtils::extensionToMimetype( "mp4" ) ); m_ext2mime.insert( "flac", TomahawkUtils::extensionToMimetype( "flac" ) ); + m_ext2mime.insert( "aiff", TomahawkUtils::extensionToMimetype( "aiff" ) ); + m_ext2mime.insert( "aif", TomahawkUtils::extensionToMimetype( "aif" ) ); } @@ -199,18 +201,16 @@ MusicScanner::listerFinished() foreach( const QString& key, m_filemtimes.keys() ) m_filesToDelete << m_filemtimes[ key ].keys().first(); - tDebug() << "Lister finished: to delete:" << m_filesToDelete; + tDebug( LOGINFO ) << "Scanning complete, saving to database. ( deleted" << m_filesToDelete.count() << "- scanned" << m_scanned << "- skipped" << m_skipped << ")"; + tDebug( LOGEXTRA ) << "Skipped the following files (no tags / no valid audio):"; + foreach ( const QString& s, m_skippedFiles ) + tDebug( LOGEXTRA ) << s; if ( m_filesToDelete.length() || m_scannedfiles.length() ) { commitBatch( m_scannedfiles, m_filesToDelete ); m_scannedfiles.clear(); m_filesToDelete.clear(); - - tDebug( LOGINFO ) << "Scanning complete, saving to database. ( scanned" << m_scanned << "skipped" << m_skipped << ")"; - tDebug( LOGEXTRA ) << "Skipped the following files (no tags / no valid audio):"; - foreach ( const QString& s, m_skippedFiles ) - tDebug( LOGEXTRA ) << s; } else cleanup(); @@ -335,9 +335,8 @@ MusicScanner::readFile( const QFileInfo& fi ) int bitrate = 0; int duration = 0; - + Tag *tag = Tag::fromFile( f ); - if ( f.audioProperties() ) { TagLib::AudioProperties *properties = f.audioProperties(); @@ -345,10 +344,14 @@ MusicScanner::readFile( const QFileInfo& fi ) bitrate = properties->bitrate(); } - QString artist = tag->artist().trimmed(); - QString album = tag->album().trimmed(); - QString track = tag->title().trimmed(); - if ( artist.isEmpty() || track.isEmpty() ) + QString artist, album, track; + if ( tag ) + { + artist = tag->artist().trimmed(); + album = tag->album().trimmed(); + track = tag->title().trimmed(); + } + if ( !tag || artist.isEmpty() || track.isEmpty() ) { // FIXME: do some clever filename guessing m_skippedFiles << fi.canonicalFilePath(); diff --git a/src/libtomahawk/taghandlers/tag.cpp b/src/libtomahawk/taghandlers/tag.cpp index 698cc0e07..6084900f6 100644 --- a/src/libtomahawk/taghandlers/tag.cpp +++ b/src/libtomahawk/taghandlers/tag.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -56,6 +57,12 @@ namespace Tomahawk if( file->tag() ) t = new OggTag( f.tag(), file->tag() ); } + else if( TagLib::RIFF::AIFF::File *file = + dynamic_cast< TagLib::RIFF::AIFF::File * >( f.file() ) ) + { + if( file->tag() ) + t = new ID3v2Tag( f.tag(), file->tag() ); + } else if( TagLib::Ogg::Speex::File *file = dynamic_cast< TagLib::Ogg::Speex::File * >( f.file() ) ) { diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index e6596cfb3..ddb19dd78 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -303,12 +303,14 @@ extensionToMimetype( const QString& extension ) s_ext2mime.insert( "mp3", "audio/mpeg" ); s_ext2mime.insert( "ogg", "application/ogg" ); s_ext2mime.insert( "oga", "application/ogg" ); - s_ext2mime.insert( "flac", "audio/flac" ); s_ext2mime.insert( "mpc", "audio/x-musepack" ); s_ext2mime.insert( "wma", "audio/x-ms-wma" ); s_ext2mime.insert( "aac", "audio/mp4" ); s_ext2mime.insert( "m4a", "audio/mp4" ); s_ext2mime.insert( "mp4", "audio/mp4" ); + s_ext2mime.insert( "flac", "audio/flac" ); + s_ext2mime.insert( "aiff", "audio/aiff" ); + s_ext2mime.insert( "aif", "audio/aiff" ); } return s_ext2mime.value( extension, "unknown" ); From 95dd12aaea32f21fdaa51a2e55897e8aa595eeb5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 10:31:22 +0200 Subject: [PATCH 261/433] * Updated ChangeLog. --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index c0b0016c6..81835c77b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,5 @@ Version 0.5.0: + * Support .aiff (AIFF mimetype) files. * Added "Stop playback after this track" context menu items. * You can now import your entire Last.fm playback history into Tomahawk. * Support for multimedia keys (Play, Pause, Next etc.) on Windows & Linux. From f35821b3b59cc7a018d9d16b1344c9d931a46775 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 1 Jun 2012 10:40:48 +0200 Subject: [PATCH 262/433] * Add an alternative OverlayWidget CTOR for regular QWidgets. --- src/libtomahawk/widgets/OverlayWidget.cpp | 74 +++++++++++++++-------- src/libtomahawk/widgets/OverlayWidget.h | 7 ++- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index 4917c84cf..aa6b846ba 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -31,32 +31,30 @@ #define OPACITY 0.70 +OverlayWidget::OverlayWidget( QWidget* parent ) + : QWidget( parent ) // this is on purpose! + , m_parent( parent ) + , m_itemView( 0 ) +{ + init(); +} + + OverlayWidget::OverlayWidget( QAbstractItemView* parent ) : QWidget( parent ) // this is on purpose! - , m_opacity( 0.00 ) , m_parent( parent ) + , m_itemView( parent ) { - setAttribute( Qt::WA_TranslucentBackground, true ); + init(); - setOpacity( m_opacity ); - - m_timer.setSingleShot( true ); - connect( &m_timer, SIGNAL( timeout() ), this, SLOT( hide() ) ); - - if ( m_parent->model() ) + if ( m_itemView->model() ) { - connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); - connect( m_parent->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); - connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); - connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); } - connect( m_parent, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); - -#ifdef Q_WS_MAC - QFont f( font() ); - f.setPointSize( f.pointSize() - 2 ); - setFont( f ); -#endif + connect( m_itemView, SIGNAL( modelChanged() ), SLOT( onViewModelChanged() ) ); } @@ -65,6 +63,24 @@ OverlayWidget::~OverlayWidget() } +void +OverlayWidget::init() +{ + setAttribute( Qt::WA_TranslucentBackground, true ); + m_opacity = 0.00; + setOpacity( m_opacity ); + + m_timer.setSingleShot( true ); + connect( &m_timer, SIGNAL( timeout() ), this, SLOT( hide() ) ); + +#ifdef Q_WS_MAC + QFont f( font() ); + f.setPointSize( f.pointSize() - 2 ); + setFont( f ); +#endif +} + + void OverlayWidget::setOpacity( qreal opacity ) { @@ -133,7 +149,10 @@ OverlayWidget::shown() const void OverlayWidget::onViewChanged() { - PlayableProxyModel* model = qobject_cast( m_parent->model() ); + if ( !m_itemView ) + return; + + PlayableProxyModel* model = qobject_cast( m_itemView->model() ); if ( m_text.isEmpty() || ( model && ( model->rowCount( QModelIndex() ) || model->isLoading() ) ) ) { @@ -149,12 +168,15 @@ OverlayWidget::onViewChanged() void OverlayWidget::onViewModelChanged() { - if ( m_parent->model() ) + if ( !m_itemView ) + return; + + if ( m_itemView->model() ) { - connect( m_parent->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); - connect( m_parent->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); - connect( m_parent->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); - connect( m_parent->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingStarted() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); + connect( m_itemView->model(), SIGNAL( loadingFinished() ), SLOT( onViewChanged() ), Qt::UniqueConnection ); onViewChanged(); } @@ -167,7 +189,7 @@ OverlayWidget::paintEvent( QPaintEvent* event ) Q_UNUSED( event ); { - QSize maxiSize = QSize( (double)m_parent->viewport()->width() * 0.70, (double)m_parent->viewport()->height() * 0.70 ); + QSize maxiSize = QSize( (double)m_parent->width() * 0.70, (double)m_parent->height() * 0.70 ); QSize prefSize = QSize( 380, 128 ); int width = qMin( maxiSize.width(), prefSize.width() ); int height = qMin( maxiSize.height(), prefSize.height() ); diff --git a/src/libtomahawk/widgets/OverlayWidget.h b/src/libtomahawk/widgets/OverlayWidget.h index 352049799..c618cd118 100644 --- a/src/libtomahawk/widgets/OverlayWidget.h +++ b/src/libtomahawk/widgets/OverlayWidget.h @@ -31,6 +31,7 @@ Q_OBJECT Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) public: + OverlayWidget( QWidget* parent ); OverlayWidget( QAbstractItemView* parent ); ~OverlayWidget(); @@ -55,10 +56,14 @@ private slots: void onViewModelChanged(); private: + void init(); + QString m_text; qreal m_opacity; - QAbstractItemView* m_parent; + QWidget* m_parent; + QAbstractItemView* m_itemView; + QTimer m_timer; }; From 6fa0f8a140525dd7287ba5c53323757c429ddaf5 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Fri, 1 Jun 2012 13:32:36 -0400 Subject: [PATCH 263/433] Crop SVG logo --- data/icons/tomahawk-icon.svg | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/data/icons/tomahawk-icon.svg b/data/icons/tomahawk-icon.svg index 6b45c0e9d..05b80614d 100644 --- a/data/icons/tomahawk-icon.svg +++ b/data/icons/tomahawk-icon.svg @@ -13,9 +13,9 @@ id="Layer_1" x="0px" y="0px" - width="841.89px" - height="595.28px" - viewBox="0 0 841.89 595.28" + width="606.2478" + height="595.49866" + viewBox="0 0 606.24779 595.49863" enable-background="new 0 0 841.89 595.28" xml:space="preserve" inkscape:version="0.48.2 r9819" @@ -32,33 +32,37 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1017" - inkscape:window-height="940" + inkscape:window-width="1440" + inkscape:window-height="794" id="namedview11" showgrid="false" - inkscape:zoom="0.79203971" - inkscape:cx="431.12552" - inkscape:cy="295.63997" - inkscape:window-x="258" - inkscape:window-y="62" + inkscape:zoom="1" + inkscape:cx="431.12548" + inkscape:cy="336.94553" + inkscape:window-x="0" + inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="Layer_1" - inkscape:snap-page="false"> + transform="matrix(7.3080643,0,0,7.1790074,-2773.1692,-1839.0104)"> Date: Fri, 1 Jun 2012 22:16:42 +0000 Subject: [PATCH 264/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 427 ++++++++++++++++++------------------ lang/tomahawk_bg.ts | 408 +++++++++++++++++------------------ lang/tomahawk_ca.ts | 407 +++++++++++++++++----------------- lang/tomahawk_de.ts | 407 +++++++++++++++++----------------- lang/tomahawk_en.ts | 407 +++++++++++++++++----------------- lang/tomahawk_es.ts | 407 +++++++++++++++++----------------- lang/tomahawk_fr.ts | 479 ++++++++++++++++++++--------------------- lang/tomahawk_ja.ts | 469 ++++++++++++++++++++-------------------- lang/tomahawk_pl.ts | 407 +++++++++++++++++----------------- lang/tomahawk_pt_BR.ts | 409 +++++++++++++++++------------------ lang/tomahawk_ru.ts | 407 +++++++++++++++++----------------- lang/tomahawk_sv.ts | 409 +++++++++++++++++------------------ lang/tomahawk_tr.ts | 407 +++++++++++++++++----------------- lang/tomahawk_zh_CN.ts | 405 +++++++++++++++++----------------- lang/tomahawk_zh_TW.ts | 404 +++++++++++++++++----------------- 15 files changed, 3061 insertions(+), 3198 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 81cabaf74..ac6733d95 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -56,7 +56,7 @@ connect and stream from you? &Listen Along - &استمع مع + &استمع مع @@ -134,7 +134,17 @@ connect and stream from you? ألبومات أخرى للفنان - + + Sorry, we could not find any other albums for this artist! + نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! + + + + Sorry, we could not find any tracks for this album! + نعتذر، لم نستطيع إيجاد أغاني أخرى لهذا الألبوم! + + + Other Albums by %1 ألبومات أخرى ل%1 @@ -142,35 +152,17 @@ connect and stream from you? AlbumModel - - Album - البوم - - - - + + All albums from %1 جميع الألبومات من %1 - + All albums جميع الألبومات - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - بعد إجراء مسح مجموعة أغانيك الخاصة ستجد ألبوماتك المضافة هنا. - - - - This collection doesn't have any recent albums. - هذه المجموعة لا تحتوي على ألبومات جديدة. - - ArtistInfoWidget @@ -193,23 +185,20 @@ connect and stream from you? Albums ألبومات - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. + + Sorry, we could not find any albums for this artist! + نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! - - This collection is currently empty. - المجموعة فارغة حاليا. + + Sorry, we could not find any related artists! + نعتذر، لم نستطيع إيجاد فنانين! - - Sorry, your filter '%1' did not match any results. - نتأسف، نظام الترشيح لم يجد شيئا تحت عنوان '%1'. + + Sorry, we could not find any top hits for this artist! + نعتذر، لم نستطيع إيجاد أغاني مشهورة جدا لهذا الفنان! @@ -294,22 +283,25 @@ connect and stream from you? CategoryAddItem - - New Playlist + Create new Playlist إنشاء قائمة أغاني جديدة - - - - + + Create new Station + إنشاء إذاعة جديدة + + + + + New Station إنشاء إذاعة جديدة - - - + + + %1 Station إذاعة %1 @@ -335,27 +327,6 @@ connect and stream from you? مسح
    - - CollectionFlatModel - - - My Collection - مجموعتي الخاصة - - - - Collection of %1 - مجموعة %1 - - - - CollectionView - - - This collection is empty. - هذه المجموعة فارغة. - - ContextWidget @@ -365,12 +336,12 @@ connect and stream from you? - + Show Footnotes أظهر الحاشية - + Hide Footnotes إخفي الحاشية @@ -463,12 +434,7 @@ connect and stream from you? تشخيص توماهوك - - Update - تحديث - - - + Copy to Clipboard نسخ إلى الحافظة @@ -644,65 +610,71 @@ connect and stream from you? PlayableModel - + Artist فنان - + Title عنوان - + Composer مؤلف - + Album البوم - + Track اغنية - + Duration مدة - + Bitrate معدل البت - + Age عمر - + Year سنة - + Size حجم - + Origin أصل - + Score علامة + + + + Name + إسم + PlaylistItemDelegate @@ -748,12 +720,12 @@ connect and stream from you? أنت - + All tracks by %1 on album %2 جميع أغاني %1 في البوم %2 - + All tracks by %1 جميع أغاني %1 @@ -799,7 +771,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + هذه المجموعة فارغة حاليا. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! هذه القائمة فارغة حاليا. أضف لها بعض الأغاني واستمتع للموسيقى! @@ -965,14 +942,24 @@ connect and stream from you? - - Show Queue - أظهر قائمة الانتظار + + Open Queue + إفتح قائمة الإنتظار - - Hide Queue - إخفي قائمة الانتظار + + The queue is currently empty. Drop something to enqueue it! + قائمة الانتظار هذه فارغة حاليا. إرمي شيئا لإضافته! + + + + Open Queue - %n item(s) + إفتح قائمة الإنتظار - %n بندإفتح قائمة الإنتظار - بند %nإفتح قائمة الإنتظار - بندين %nإفتح قائمة الإنتظار - %n بنودإفتح قائمة الإنتظار - %n بنودإفتح قائمة الإنتظار - %n بنود + + + + Close Queue + أغلق قائمة الإنتظار @@ -1146,7 +1133,7 @@ connect and stream from you? Offline - خارج الهواء + غير متصل @@ -1156,7 +1143,7 @@ connect and stream from you? Online - على الهواء + متصل @@ -1189,17 +1176,17 @@ connect and stream from you? الأغاني التي إستمعت إليها مؤخرا - + New Additions الإضافة الجديدة - + My recent activity نشاطاتي الأخيرة - + Recent activity from %1 النشاطات المؤخرة ل %1 @@ -1207,31 +1194,36 @@ connect and stream from you? SourceItem - + Collection مجموعة - + Latest Additions أحدث الإضافات - + Recently Played تم الاستماع لها مؤخرا - + Loved Tracks الأغاني المحبوبة - + SuperCollection سوبر كولكشن + + + Sorry, we could not find any loved tracks! + نعتذر، لم نستطيع إيجاد أغاني محبوبة! + Latest additions to your collection @@ -1243,20 +1235,30 @@ connect and stream from you? آخر إضافات على مجموعة %1 - + + Sorry, we could not find any recent additions! + نعتذر، لم نستطيع إيجاد إضافة جديدة! + + + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Your recently played tracks الأغاني التي إستمعت إليها مؤخرا - + %1's recently played tracks الأغاني التي سمعها مؤخرا %1 + + + Sorry, we could not find any recent plays! + نعتذر، لم نستطيع إيجاد أغاني مسموعة مؤخرا! + SourceTreeView @@ -1314,15 +1316,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? - هل ترغب في حذف %1 <b> "%2" </b>؟ + e.g. Would you like to delete the playlist named Foobar? + هل ترغب في حذف %1 <b>"%2"</b>؟ - + Save XSPF حفظ XSPF - + Playlists (*.xspf) قوائم أغاني (*.xspf) @@ -1624,12 +1627,12 @@ connect and stream from you? Connecting... - يجرى الاتصال... + جاري الاتصال... Offline - خارج الهواء + غير متصل @@ -2018,32 +2021,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks الأغاني المحبوبة الأكثر شهرة - + Your loved tracks الأغاني التي أحببتها - + %1's loved tracks الأغاني المحبوبة ل%1 - + The most loved tracks from all your friends الأغاني المحبوبة كثيرا بين أصدقائك - + All of your loved tracks جميع الأغاني التي أحببتها - + All of %1's loved tracks جميع الأغاني المحبوبة ل%1 @@ -2123,17 +2126,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! أدخل بعض الترشيحات أعلاه لتوزيع هذه الإذاعة! - + Press Generate to get started! إضغط "توليد" لتبدأ! - + Add some filters above, and press Generate to get started! أدخل بعض الترشيحات أعلاه ثم iضغط "توليد" لتبدأ! @@ -2685,7 +2688,7 @@ Try tweaking the filters for a new set of songs to play. &Listen Along - &تابع الاستماع + &استمع مع @@ -2959,12 +2962,12 @@ enter the displayed PIN number here: Show Offline Sources - أظهر مصادر خارج الهواء + أظهر المصادر الغير متصلة Hide Offline Sources - إخفي مصادر خارج الهواء + إخفي المصادر الغير متصلة @@ -3003,7 +3006,7 @@ enter the displayed PIN number here: - + Play إستمع @@ -3048,142 +3051,147 @@ enter the displayed PIN number here: بحث شامل... - - + + Check For Updates... التحقق من التحديثات... - - - + + + Connect To Peer ربط بالند - + Enter peer address: أدخل عنوان الند: - + Enter peer port: أدخل بوابة الند: - + Enter peer key: أدخل مفتاح الند: - + XSPF Error خطأ XSPF - + This is not a valid XSPF playlist. قائمة الأغاني XSPF هذه ليست صالحة. - + Failed to save tracks فشل في حفظ الأغاني - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. - + + Station + إذاعة + + + Create New Station إنشاء قائمة أغاني جديدة - + Name: الاسم: - - New Station - إذاعة جديدة + + Playlist + قائمة الأغاني - - New Playlist - قائمة أغاني جديدة + + Automatic Playlist + قائمة أغاني أوتوماتيكية - + Pause تعليق - + Go &offline - إذهب &خارج الهواء + أصبح &غير متصل - + Go &online اصبح &متصل - + Authentication Error خطأ في المصادقة - + Error connecting to SIP: Authentication failed! خطأ في الاتصال بسيب (SIP): فشلت المصادقة! - + %1 by %2 track, artist name %1 من قبل %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ - + Thanks to: شكر لكل من: - + About Tomahawk عن توماهوك @@ -3311,28 +3319,33 @@ enter the displayed PIN number here: Similar Tracks أغاني قريبة + + + Sorry, but we could not find similar tracks for this song! + نعتذر، لم نستطيع إيجاد أغاني قريبة من هذه الأغنية! + - + You've listened to this track %n time(s). لقد استمعت إلى هذه الأغنية %n مرة.لقد استمعت إلى هذه الأغنية مرة %n.لقد استمعت إلى هذه الأغنية مرتين %n.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات. - + You've never listened to this track before. لم تستمع لهذه الأغنية من قبل. - + You first listened to it on %1. استمعت إليها أولاً في %1. - + You've listened to %1 %n time(s). لقد استمعت إلى %1 %n مرة.لقد استمعت إلى %1 مرة %n.لقد استمعت إلى %1 مرتين %n.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات. - + You've never listened to %1 before. لم تستمع إلى %1 من قبل. @@ -3340,7 +3353,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. عذراً، ترشيحك "%1" لم يطابق أي نتائج. @@ -3369,63 +3382,31 @@ enter the displayed PIN number here: TreeModel - - Name - اسم - - - - Duration - مدة - - - - Bitrate - معدل البت - - - - Age - عمر - - - - Year - سنة - - - - Size - حجم - - - - Origin - أصل - - - - Composer - مؤلف - - - + All Artists جميع الفنانين - - + + My Collection مجموعتي الخاصة - - + + Collection of %1 مجموعة %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + نتأسف، نظام الترشيح لم يجد شيئا تحت عنوان '%1'. + + TwitterConfigWidget @@ -3502,27 +3483,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + بعد إجراء مسح مجموعة أغانيك الخاصة ستجد أغانيك هنا. + + + + This collection is empty. + هذه المجموعة فارغة. + + + SuperCollection سوبر كولكشن - + Combined libraries of all your online friends مكتبات مجمعة لكل اصحابك المتصلين - + All available albums جميع الألبومات الجديدة - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Recently played tracks from all your friends جميع الأغاني التي استمع إليها أصدقائك مؤخرا @@ -3558,7 +3549,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts الرسوم البيانية @@ -3706,7 +3697,7 @@ Lyrics for "%1" by %2: Close - أغلق + اغلاق diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 1c6a97d26..8acbd8195 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -133,7 +133,17 @@ connect and stream from you? Други албуми на този артист - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Други албуми от %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Албум - - - - + + All albums from %1 Всички албуми на %1 - + All albums Всички албуми - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - След като бъде сканирана музикалната ти колекция, ще откриеш тук най-скоро добавените албуми. - - - - This collection doesn't have any recent albums. - В тази колекция все още няма добавени наскоро албуми. - - ArtistInfoWidget @@ -192,24 +184,20 @@ connect and stream from you? Albums Албуми - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - След като приключи сканирането на музикалната ти колекция, ще откриеш музиката си тук. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Базата данни с песни е празна. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Съжалявам. -Твоят филтър '%1' не върна никакъв резултат. + + Sorry, we could not find any top hits for this artist! + @@ -294,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Нов списък + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Нова станция - - - + + + %1 Station %1 Станция @@ -335,27 +326,6 @@ connect and stream from you? Изчисти - - CollectionFlatModel - - - My Collection - Моята колекция - - - - Collection of %1 - Колекцията на %1 - - - - CollectionView - - - This collection is empty. - Тази колекция е празна. - - ContextWidget @@ -365,12 +335,12 @@ connect and stream from you? - + Show Footnotes Покажи подробности - + Hide Footnotes Скрий подробности @@ -466,12 +436,7 @@ Tomahaw създаде доклад относно това и изпращай Диагностична информация относно Tomahawk - - Update - Обнови - - - + Copy to Clipboard Копирай в буферът @@ -647,65 +612,71 @@ Tomahaw създаде доклад относно това и изпращай PlayableModel - + Artist Артист - + Title Име - + Composer Композитор - + Album Албум - + Track Песен - + Duration Продължителност - + Bitrate Качество - + Age Възраст - + Year Година - + Size Големина - + Origin Източник - + Score Резултат + + + + Name + + PlaylistItemDelegate @@ -751,12 +722,12 @@ Tomahaw създаде доклад относно това и изпращай ти - + All tracks by %1 on album %2 Всички песни от %1, от албум %2 - + All tracks by %1 Всички песни от %1 @@ -802,7 +773,12 @@ Tomahaw създаде доклад относно това и изпращай PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Този списък в момента е празен. Добави няколко изпълнения и се наслади на музиката! @@ -966,14 +942,24 @@ Tomahaw създаде доклад относно това и изпращай - - Show Queue - Покажи опашката + + Open Queue + - - Hide Queue - Скрий опашката + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1190,17 +1176,17 @@ Tomahaw създаде доклад относно това и изпращай Наскоро изпълнени песни - + New Additions Нови попълнения - + My recent activity Скорошна активност - + Recent activity from %1 Скорошна активност на %1 @@ -1208,32 +1194,37 @@ Tomahaw създаде доклад относно това и изпращай SourceItem - + Collection Колекция - + Latest Additions Последно добавени - + Recently Played Наскоро изпълнени песни - + Loved Tracks Харесани песни - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1245,20 +1236,30 @@ Tomahaw създаде доклад относно това и изпращай Последно добавени в колекцията на %1 - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks Наскоро изпълнени песни - + Your recently played tracks Наскоро изпълнени песни от теб - + %1's recently played tracks Наскоро изпълнените песни от %1 + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1316,15 +1317,16 @@ Tomahaw създаде доклад относно това и изпращай Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -2027,32 +2029,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Най-харесвани песни - + Your loved tracks Песните, които харесам. - + %1's loved tracks Песните, каресвани от %1 - + The most loved tracks from all your friends Най-харесваните песни от всички твои приятели. - + All of your loved tracks Всички песни, които харесвам. - + All of %1's loved tracks Всички песни, харесвани от %1 @@ -2131,17 +2133,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Добави няколко критерия, за да разпространиш тази станция - + Press Generate to get started! Натисни "Генерирай" за да почне просвирване. - + Add some filters above, and press Generate to get started! Добави няколко критерия и натисни "Генерирай" за да почне просвирване. @@ -3011,7 +3013,7 @@ enter the displayed PIN number here: - + Play Изпълни @@ -3056,145 +3058,150 @@ enter the displayed PIN number here: Глобално търсене... - - + + Check For Updates... Провери за обновления... - - - + + + Connect To Peer Свържи се с друг потребител - + Enter peer address: Въведи адресът на отдалеченият потребител: - + Enter peer port: Въведи порт: - + Enter peer key: Въведи ключът за удостоверяване: - + XSPF Error XSPF Грешка - + This is not a valid XSPF playlist. Това не е валиден XSPF списък - + Failed to save tracks Не мога да запазя списъкът с песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Някои от песните в този списък нямат артист и заглавие. Те ще бъдат игнорирани. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраната песен - тя ще бъде прескочена. Моля, увери се, че са инсталирани подходящ Phonon и приставки. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Съжалявам. Има проблем с достъпа до твоето аудио устройство или избраната песен. Тя ще бъде пропусната. - + + Station + + + + Create New Station Създай нова станция - + Name: Име: - - New Station - Нова станция + + Playlist + - - New Playlist - Нов списък + + Automatic Playlist + - + Pause Пауза - + Go &offline Излез &извън линия - + Go &online Свържи &се - + Authentication Error Грешка при удостоверяване - + Error connecting to SIP: Authentication failed! Грешка при свързване: Неуспешно удостоверяване! - + %1 by %2 track, artist name %1 от %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Всички права - запазени. 2010 - 2012 - + Thanks to: Благодарности на: - + About Tomahawk Относно Tomahawk @@ -3322,28 +3329,33 @@ enter the displayed PIN number here: Similar Tracks Подобни песни + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Ти си слушал тази песен %n път(и)Ти си слушал тази песен %n път(и) - + You've never listened to this track before. Никога не си слушал тази песен преди - + You first listened to it on %1. Първоначално си я слушал на %1 - + You've listened to %1 %n time(s). Слушал си %1 път(и)Слушал си %1 %n път(и) - + You've never listened to %1 before. Никога не си слушал %1 преди @@ -3351,7 +3363,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Съжалявам, твоят филтър %1 не върна никакъв резултат. @@ -3380,63 +3392,31 @@ enter the displayed PIN number here: TreeModel - - Name - Име - - - - Duration - Продължителност - - - - Bitrate - Качество - - - - Age - Възраст - - - - Year - Година - - - - Size - Размер - - - - Origin - Произход - - - - Composer - Композитор - - - + All Artists Всички артисти - - + + My Collection Моята колекция - - + + Collection of %1 Колекцията на %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3514,28 +3494,38 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Combined libraries of all your online friends Обща колекция с всичките ми приятели на линия - + All available albums Всички налични албуми - + Recently Played Tracks Наскоро изпълени песни - + Recently played tracks from all your friends Наскоро изпълнени песни от всичките ти приятели @@ -3571,7 +3561,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Класации diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 15d030ae2..f026b0666 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -133,7 +133,17 @@ connect and stream from you? Altres Àlbums de l'Artista - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Altres Àlbums de %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Àlbum - - - - + + All albums from %1 Tots els Àlbums de %1 - + All albums Tots els Àlbums - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Després d'escanejar la vostra col·lecció musical, aquí trobareu els àlbums afegits últimament. - - - - This collection doesn't have any recent albums. - Aquesta col·lecció no té àlbums recents. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Àlbums - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Després d'escanejar la vostra col·lecció musical, aquí trobareu les cançons afegides últimament. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Aquesta col·lecció es troba buida actualment. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - El filtre '%1' no ha obtingut cap resultat. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nova llista de reproducció + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nova Emissora - - - + + + %1 Station Emissora %1 @@ -334,27 +326,6 @@ connect and stream from you? Suprimeix - - CollectionFlatModel - - - My Collection - La meva Col·lecció - - - - Collection of %1 - Col·lecció de %1 - - - - CollectionView - - - This collection is empty. - Aquesta col·lecció és buida. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Mostra les Notes al peu - + Hide Footnotes Amaga les Notes al peu @@ -462,12 +433,7 @@ connect and stream from you? Diagnòstics de Tomahawk - - Update - Actualitza - - - + Copy to Clipboard Copia al Porta-retalls @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? - + All tracks by %1 on album %2 Totes les cançons de %1 a l'àlbum %2 - + All tracks by %1 Totes les cançons de %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Aquesta llista es troba buida. Afegiu-hi algunes cançons i gaudiu de la música! @@ -963,14 +940,24 @@ connect and stream from you? - - Show Queue - Mostra la Cua + + Open Queue + - - Hide Queue - Amaga la Cua + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1187,17 +1174,17 @@ connect and stream from you? Cançons Escoltades Recentment - + New Additions Novetats - + My recent activity La meva activitat recent - + Recent activity from %1 Activitat recent de %1 @@ -1205,31 +1192,36 @@ connect and stream from you? SourceItem - + Collection Col·lecció - + Latest Additions Darreres Novetats - + Recently Played Escoltades Recentment - + Loved Tracks Cançons Preferides - + SuperCollection SuperCol·lecció + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1241,20 +1233,30 @@ connect and stream from you? Darreres novetats a la col·lecció de %1 - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks Cançons Escoltades Recentment - + Your recently played tracks Cançons Escoltades Recentment - + %1's recently played tracks Cançons Escoltades Recentment per %1 + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1312,15 +1314,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -2017,32 +2020,32 @@ Torneu a autenticar-vos. Tomahawk::CustomPlaylistView - + Top Loved Tracks Top de Cançons Preferides - + Your loved tracks Les meves cançons preferides - + %1's loved tracks Les cançons preferides de %1 - + The most loved tracks from all your friends Les cançons preferides de tots els amics - + All of your loved tracks Totes les meves cançons preferides - + All of %1's loved tracks Totes les cançons preferides de %1 @@ -2122,17 +2125,17 @@ Canvieu els filtres o intenteu-ho de nou. Tomahawk::DynamicView - + Add some filters above to seed this station! Afegeiu slguns filtres per omplir aquesta emissora! - + Press Generate to get started! Premeu Genera per començar! - + Add some filters above, and press Generate to get started! Afegeiu alguns filtres i premeu Genera per començar! @@ -3002,7 +3005,7 @@ introduïu el PIN aquí: - + Play Reprodueix @@ -3047,142 +3050,147 @@ introduïu el PIN aquí: Cerca Global... - - + + Check For Updates... Comprova les actualitzacions... - - - + + + Connect To Peer Connexió Remota - + Enter peer address: Introduïu l'adreça remota: - + Enter peer port: Introduïu el port remot: - + Enter peer key: Introduïu la clau remota: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. No és una llista XSPF vàlida. - + Failed to save tracks Error en desar les cançons - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunes cançons de la llista no contenen ni artista ni titol i s'han ignorat. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Hi ha un problema per accedir al dispositiu de so o a la cançó. La cançó actual s'ha saltat. Assegureu-vos que teniu un back.end de Phonon adequant i els plugins necessaris instal·lats. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Hi ha un problema per accedir al dispositiu de so o a la cançó, la cançó actual s'ha saltat. - + + Station + + + + Create New Station Crea una Nova Emissora - + Name: Nom: - - New Station - Nova Emissora + + Playlist + - - New Playlist - Nova llista de reproducció + + Automatic Playlist + - + Pause Pausa - + Go &offline &Desconnecta't - + Go &online &Connecta't - + Authentication Error Error d'autentificació - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Quant a Tomahawk @@ -3310,28 +3318,33 @@ introduïu el PIN aquí: Similar Tracks Cançons Semblants + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Heu escoltat aquesta cançó %n cop.Heu escoltat aquesta cançó %n cops. - + You've never listened to this track before. No heu escoltat mai aquesta cançó abans. - + You first listened to it on %1. Vau escoltar aquesta cançó per primer cop el %1. - + You've listened to %1 %n time(s). Heu escoltat %1 %n cop.Heu escoltat %1 %n cops. - + You've never listened to %1 before. No heu escoltat mai %1 abans. @@ -3339,7 +3352,7 @@ introduïu el PIN aquí: TrackView - + Sorry, your filter '%1' did not match any results. El filtre '%1' no ha obtingut cap resultat. @@ -3368,63 +3381,31 @@ introduïu el PIN aquí: TreeModel - - Name - Nom - - - - Duration - Durada - - - - Bitrate - Bitrate - - - - Age - Edat - - - - Year - Any - - - - Size - Mida - - - - Origin - Origen - - - - Composer - Compositor - - - + All Artists Tots els Artistes - - + + My Collection La meva Col·lecció - - + + Collection of %1 Col·lecció de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3501,27 +3482,37 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperCol·lecció - + Combined libraries of all your online friends Biblioteques combinades de tots els amis en línia - + All available albums Tots els àlbums disponibles - + Recently Played Tracks Cançons Escoltades Recentment - + Recently played tracks from all your friends Cançons escoltades recentment pels amics @@ -3557,7 +3548,7 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant WhatsHotWidget - + Charts Llistes diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index c6e335b6b..39c221710 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -133,7 +133,17 @@ connect and stream from you? Andere Alben des Künstlers - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Andere Alben von %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 Alle Alben von %1 - + All albums Alle Alben - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Nachdem Tomahawk deine Sammlung durchsucht hast siehst du hier deine neuesten Alben. - - - - This collection doesn't have any recent albums. - Diese Sammlung ist leer. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Alben - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Nachdem Tomahawk deine Sammlung durchsucht hat siehst du deine Lieder hier. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Diese Sammlung is momentan leer. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Neue Playliste + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Neue Station - - - + + + %1 Station %1 Station @@ -334,27 +326,6 @@ connect and stream from you? Leeren - - CollectionFlatModel - - - My Collection - Meine Sammlung - - - - Collection of %1 - Sammlung von %1 - - - - CollectionView - - - This collection is empty. - Diese Sammlung ist leer. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Footnotes einblenden - + Hide Footnotes Footnotes ausblenden @@ -462,12 +433,7 @@ connect and stream from you? Tomahawk Diagnose Tool - - Update - Aktualisieren - - - + Copy to Clipboard In die Zwischenablage kopieren @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist Künstler - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? dir - + All tracks by %1 on album %2 Alle Lieder von %1 auf dem Album %2 - + All tracks by %1 Alle Lieder von %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Diese Playliste ist derzeit leer. Füge einige Stücke hinzu und genieße die Musik! @@ -963,14 +940,24 @@ connect and stream from you? - - Show Queue - Warteschlange einblenden + + Open Queue + - - Hide Queue - Warteschlange ausblenden + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1187,17 +1174,17 @@ connect and stream from you? Kürzlich gehörte Lieder - + New Additions Kürzlich hinzugekommen - + My recent activity Meine letzten Aktivitäten - + Recent activity from %1 Die letzten Aktivitäten von %1 @@ -1205,31 +1192,36 @@ connect and stream from you? SourceItem - + Collection Sammlung - + Latest Additions Kürzlich hinzugekommen - + Recently Played Kürzlich gehörte Lieder - + Loved Tracks Lieblingslieder - + SuperCollection Supersammlung + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1241,20 +1233,30 @@ connect and stream from you? Neueste Lieder in %1's Sammlung - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks Zuletzt gehörte Lieder - + Your recently played tracks Deine zuletzt gehörten Lieder - + %1's recently played tracks %1's zuletzt gehörte Lieder + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1312,15 +1314,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -2012,32 +2015,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Meist geliebte Lieder - + Your loved tracks Deine Lieblingslieder - + %1's loved tracks Die Lieblingslieder von %1 - + The most loved tracks from all your friends Die Lieblingslieder deiner Freunde - + All of your loved tracks All deine Lieblingslieder - + All of %1's loved tracks Alle Lieblingslieder von %1 @@ -2117,17 +2120,17 @@ Bitte ändere den Filter oder versuche es erneut. Tomahawk::DynamicView - + Add some filters above to seed this station! Füge einige Filter hinzu, um diese Station zu starten! - + Press Generate to get started! Drücke Erzeugen, und los geht's! - + Add some filters above, and press Generate to get started! Füge oben einige Filter hinzu und drücke Erzeugen um loszulegen! @@ -2997,7 +3000,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: - + Play Abspielen @@ -3042,142 +3045,147 @@ Tomahawk auf Twitter's Website authentifiziert hast: Globale Suche... - - + + Check For Updates... Nach Updates suchen... - - - + + + Connect To Peer Mit anderem Tomahawk verbinden - + Enter peer address: Gib die Adresse der Gegenstelle ein: - + Enter peer port: Gib den Port der Gegenstelle ein: - + Enter peer key: Gib den Schlüssel der Gegenstelle ein: - + XSPF Error XSPF-Fehler - + This is not a valid XSPF playlist. Dies ist keine gültige XSPF-Playliste. - + Failed to save tracks Konnte Stücke nicht abspeichern - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Einige Stücke in der Playliste enthalten weder Künstler noch Titel. Diese werden ignoriert. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. Vergewisser dich, dass ein geignetes Phonon-Backend mitsamt benötigten Plugins installiert ist. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. - + + Station + + + + Create New Station Neue Station erstellen - + Name: Name: - - New Station - Neue Station + + Playlist + - - New Playlist - Neue Playliste + + Automatic Playlist + - + Pause Pause - + Go &offline Verbindung &trennen - + Go &online &Verbindung herstellen - + Authentication Error Authentifizierungsfehler - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 von %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Über Tomahawk @@ -3305,28 +3313,33 @@ Tomahawk auf Twitter's Website authentifiziert hast: Similar Tracks Ähnliche Lieder + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Du hast dieses Lied einmal gehört.Du hast dieses Lied %n mal gehört. - + You've never listened to this track before. Du hast dieses Lied noch nie angehört. - + You first listened to it on %1. Du hast dieses Lied zum ersten mal am %1 gehört. - + You've listened to %1 %n time(s). Du hast %1 einmal angehört.Du hast %1 %n mal angehört. - + You've never listened to %1 before. Du hast %1 vorher noch nie gehört. @@ -3334,7 +3347,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3363,63 +3376,31 @@ Tomahawk auf Twitter's Website authentifiziert hast: TreeModel - - Name - Name - - - - Duration - Dauer - - - - Bitrate - Bitrate - - - - Age - Alter - - - - Year - Jahr - - - - Size - Größe - - - - Origin - Quelle - - - - Composer - Komponist - - - + All Artists Alle Künstler - - + + My Collection Meine Sammlung - - + + Collection of %1 Sammlung von %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3491,27 +3472,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperCollection - + Combined libraries of all your online friends Kombinierte Sammlung all deiner Freunde - + All available albums Alle verfügbaren Alben - + Recently Played Tracks Zuletzt gehörte Lieder - + Recently played tracks from all your friends Zuletzt gehörte Lieder all deiner Freunde @@ -3547,7 +3538,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Charts diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index b75f263f6..eea2c3d51 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -134,7 +134,17 @@ connect and stream from you? Other Albums by Artist - + + Sorry, we could not find any other albums for this artist! + Sorry, we could not find any other albums for this artist! + + + + Sorry, we could not find any tracks for this album! + Sorry, we could not find any tracks for this album! + + + Other Albums by %1 Other Albums by %1 @@ -142,35 +152,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 All albums from %1 - + All albums All albums - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - After you have scanned your music collection you will find your latest album additions right here. - - - - This collection doesn't have any recent albums. - This collection doesn't have any recent albums. - - ArtistInfoWidget @@ -193,23 +185,20 @@ connect and stream from you? Albums Albums - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - After you have scanned your music collection you will find your tracks right here. + + Sorry, we could not find any albums for this artist! + Sorry, we could not find any albums for this artist! - - This collection is currently empty. - This collection is currently empty. + + Sorry, we could not find any related artists! + Sorry, we could not find any related artists! - - Sorry, your filter '%1' did not match any results. - Sorry, your filter '%1' did not match any results. + + Sorry, we could not find any top hits for this artist! + Sorry, we could not find any top hits for this artist! @@ -294,22 +283,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - New Playlist + Create new Playlist + Create new Playlist - - - - + + Create new Station + Create new Station + + + + + New Station New Station - - - + + + %1 Station %1 Station @@ -335,27 +327,6 @@ connect and stream from you? Clear - - CollectionFlatModel - - - My Collection - My Collection - - - - Collection of %1 - Collection of %1 - - - - CollectionView - - - This collection is empty. - This collection is empty. - - ContextWidget @@ -365,12 +336,12 @@ connect and stream from you? - + Show Footnotes Show Footnotes - + Hide Footnotes Hide Footnotes @@ -463,12 +434,7 @@ connect and stream from you? Tomahawk Diagnostics - - Update - Update - - - + Copy to Clipboard Copy to Clipboard @@ -644,65 +610,71 @@ connect and stream from you? PlayableModel - + Artist Artist - + Title Title - + Composer Composer - + Album Album - + Track Track - + Duration Duration - + Bitrate Bitrate - + Age Age - + Year Year - + Size Size - + Origin Origin - + Score Score + + + + Name + Name + PlaylistItemDelegate @@ -748,12 +720,12 @@ connect and stream from you? you - + All tracks by %1 on album %2 All tracks by %1 on album %2 - + All tracks by %1 All tracks by %1 @@ -799,7 +771,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + This playlist is currently empty. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -964,14 +941,24 @@ connect and stream from you? - - Show Queue - Show Queue + + Open Queue + Open Queue - - Hide Queue - Hide Queue + + The queue is currently empty. Drop something to enqueue it! + The queue is currently empty. Drop something to enqueue it! + + + + Open Queue - %n item(s) + Open Queue - %n item(s)Open Queue - %n item(s) + + + + Close Queue + Close Queue @@ -1188,17 +1175,17 @@ connect and stream from you? Recently Played Tracks - + New Additions New Additions - + My recent activity My recent activity - + Recent activity from %1 Recent activity from %1 @@ -1206,31 +1193,36 @@ connect and stream from you? SourceItem - + Collection Collection - + Latest Additions Latest Additions - + Recently Played Recently Played - + Loved Tracks Loved Tracks - + SuperCollection SuperCollection + + + Sorry, we could not find any loved tracks! + Sorry, we could not find any loved tracks! + Latest additions to your collection @@ -1242,20 +1234,30 @@ connect and stream from you? Latest additions to %1's collection - + + Sorry, we could not find any recent additions! + Sorry, we could not find any recent additions! + + + Recently Played Tracks Recently Played Tracks - + Your recently played tracks Your recently played tracks - + %1's recently played tracks %1's recently played tracks + + + Sorry, we could not find any recent plays! + Sorry, we could not find any recent plays! + SourceTreeView @@ -1313,15 +1315,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -2018,32 +2021,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Top Loved Tracks - + Your loved tracks Your loved tracks - + %1's loved tracks %1's loved tracks - + The most loved tracks from all your friends The most loved tracks from all your friends - + All of your loved tracks All of your loved tracks - + All of %1's loved tracks All of %1's loved tracks @@ -2123,17 +2126,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Add some filters above to seed this station! - + Press Generate to get started! Press Generate to get started! - + Add some filters above, and press Generate to get started! Add some filters above, and press Generate to get started! @@ -3003,7 +3006,7 @@ enter the displayed PIN number here: - + Play Play @@ -3048,142 +3051,147 @@ enter the displayed PIN number here: Global Search... - - + + Check For Updates... Check For Updates... - - - + + + Connect To Peer Connect To Peer - + Enter peer address: Enter peer address: - + Enter peer port: Enter peer port: - + Enter peer key: Enter peer key: - + XSPF Error XSPF Error - + This is not a valid XSPF playlist. This is not a valid XSPF playlist. - + Failed to save tracks Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + Station + + + Create New Station Create New Station - + Name: Name: - - New Station - New Station + + Playlist + Playlist - - New Playlist - New Playlist + + Automatic Playlist + Automatic Playlist - + Pause Pause - + Go &offline Go &offline - + Go &online Go &online - + Authentication Error Authentication Error - + Error connecting to SIP: Authentication failed! Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Copyright 2010 - 2012 - + Thanks to: Thanks to: - + About Tomahawk About Tomahawk @@ -3311,28 +3319,33 @@ enter the displayed PIN number here: Similar Tracks Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + Sorry, but we could not find similar tracks for this song! + - + You've listened to this track %n time(s). You've listened to this track %n time(s).You've listened to this track %n time(s). - + You've never listened to this track before. You've never listened to this track before. - + You first listened to it on %1. You first listened to it on %1. - + You've listened to %1 %n time(s). You've listened to %1 %n time(s).You've listened to %1 %n time(s). - + You've never listened to %1 before. You've never listened to %1 before. @@ -3340,7 +3353,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Sorry, your filter '%1' did not match any results. @@ -3369,63 +3382,31 @@ enter the displayed PIN number here: TreeModel - - Name - Name - - - - Duration - Duration - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Year - - - - Size - Size - - - - Origin - Origin - - - - Composer - Composer - - - + All Artists All Artists - - + + My Collection My Collection - - + + Collection of %1 Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + Sorry, your filter '%1' did not match any results. + + TwitterConfigWidget @@ -3502,27 +3483,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + After you have scanned your music collection you will find your tracks right here. + + + + This collection is empty. + This collection is empty. + + + SuperCollection SuperCollection - + Combined libraries of all your online friends Combined libraries of all your online friends - + All available albums All available albums - + Recently Played Tracks Recently Played Tracks - + Recently played tracks from all your friends Recently played tracks from all your friends @@ -3558,7 +3549,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Charts diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 4b8c763e7..6b4f6755d 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -133,7 +133,17 @@ connect and stream from you? Otros álbumes por el artista - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Otros álbumes por %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Álbum - - - - + + All albums from %1 Todos los álbumes de %1 - + All albums Todos los álbumes - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Tras haber escaneado su colección aquí encontrará los últimos álbumes añadidos. - - - - This collection doesn't have any recent albums. - Esta colección no tiene álbumes recientes. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Álbumes - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Tras haber escaneado su colección aquí encontrará las últimas pistas añadidas. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Esta colección está vacía. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Tu filtro '%1' no reportó ningún resultado. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nueva lista de reproducción + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nueva estación - - - + + + %1 Station %1 estación @@ -334,27 +326,6 @@ connect and stream from you? Limpiar - - CollectionFlatModel - - - My Collection - Mi colección - - - - Collection of %1 - Colección de %1 - - - - CollectionView - - - This collection is empty. - Esta colección está vacía. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Mostrar información de contexto - + Hide Footnotes Ocultar información de contexto @@ -462,12 +433,7 @@ connect and stream from you? Diagnósticos de Tomahawk - - Update - Actualizar - - - + Copy to Clipboard Copiar al portapapeles @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? usted - + All tracks by %1 on album %2 Todas las pistas de %1 en el álbum %2 - + All tracks by %1 Todas las pistas de %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reproducción está vacía. ¡Añada algunas pistas y disfrute de la música! @@ -962,14 +939,24 @@ connect and stream from you? - - Show Queue - Mostrar cola + + Open Queue + - - Hide Queue - Ocultar cola + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1186,17 +1173,17 @@ connect and stream from you? Pistas reproducidas recientemente - + New Additions Nuevas adiciones - + My recent activity Mi actividad reciente - + Recent activity from %1 Actividad reciente de %1 @@ -1204,31 +1191,36 @@ connect and stream from you? SourceItem - + Collection Colección - + Latest Additions Añadidos recientemente - + Recently Played Reproducido recientemente - + Loved Tracks Pistas favoritas - + SuperCollection SuperColección + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1240,20 +1232,30 @@ connect and stream from you? Últimas novedadoes en la colección de %1 - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks Temas Escuchados Recientemente - + Your recently played tracks Mis canciones escuchadas recientemente - + %1's recently played tracks Las canciones escuchadas recientemente por %1 + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1311,15 +1313,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -2016,32 +2019,32 @@ Hay que volverse a autenticar. Tomahawk::CustomPlaylistView - + Top Loved Tracks Pistas favoritas - + Your loved tracks Tus pistas favoritas - + %1's loved tracks Pistas favoritas de %1 - + The most loved tracks from all your friends Las pistas favoritas de tus amigos - + All of your loved tracks Todas tus pistas favoritas - + All of %1's loved tracks Todas las pistas favoritas de %1 @@ -2121,17 +2124,17 @@ Por favor, cambie los filtros o inténtelo de nuevo. Tomahawk::DynamicView - + Add some filters above to seed this station! ¡Añada algunos filtros para la estación! - + Press Generate to get started! ¡Seleccione Generar para comenzar! - + Add some filters above, and press Generate to get started! ¡Añada algunos filtros, y seleccione Generar para comenzar! @@ -3001,7 +3004,7 @@ introduzca su número PIN aquí: - + Play Reproducir @@ -3046,142 +3049,147 @@ introduzca su número PIN aquí: Búsqueda global... - - + + Check For Updates... Buscar actualizaciones... - - - + + + Connect To Peer Conectar a un par - + Enter peer address: Introducir dirección del par: - + Enter peer port: Introducir puerto del par: - + Enter peer key: Introducir contraseña del par: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. Esta no es una lista de reproducción XSPF válida. - + Failed to save tracks Fallo al guardar pistas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunas pistas en la lista de reproducción no contienen artista ni título. Serán ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. Asegúrese de que ha instalado un backend de Phonon adecuado y los plugins necesarios. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. - + + Station + + + + Create New Station Crear nueva estación - + Name: Nombre: - - New Station - Nueva estación + + Playlist + - - New Playlist - Nueva lista de reproducción + + Automatic Playlist + - + Pause Pausar - + Go &offline &Desconectarse - + Go &online &Conectarse - + Authentication Error Error de autenticación - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 por %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Acerca de Tomahawk @@ -3309,28 +3317,33 @@ introduzca su número PIN aquí: Similar Tracks Temas Similares + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). Ha escuchado esta canción %n vez.Ha escuchado esta canción %n veces. - + You've never listened to this track before. Nunca ha escuchado este tema antes. - + You first listened to it on %1. Escuchó este tema pro primera vez en %1. - + You've listened to %1 %n time(s). Ha escuchado %1 %n vez.Ha escuchado %1 %n veces. - + You've never listened to %1 before. Nunca ha escuchado %1 antes. @@ -3338,7 +3351,7 @@ introduzca su número PIN aquí: TrackView - + Sorry, your filter '%1' did not match any results. Lo siento, tu filtro '%1' no ha encontrado resultados. @@ -3367,63 +3380,31 @@ introduzca su número PIN aquí: TreeModel - - Name - Nombre - - - - Duration - Duración - - - - Bitrate - Bitrate - - - - Age - Edad - - - - Year - Año - - - - Size - Tamaño - - - - Origin - Origen - - - - Composer - Compositor - - - + All Artists Todos los artistas - - + + My Collection Mi colección - - + + Collection of %1 Colección de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3500,27 +3481,37 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperColección - + Combined libraries of all your online friends Bibliotecas combinadas de todos tus amigos conectados - + All available albums Todos los álbumes disponibles - + Recently Played Tracks Temas Escuchados Recientemente - + Recently played tracks from all your friends Temas escuchados recientemente por mis amigos @@ -3556,7 +3547,7 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en WhatsHotWidget - + Charts Listas de éxitos diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index da60d42b3..8a69e7dbe 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -134,43 +134,35 @@ se connecter et streamer depuis chez vous ? Tous les albums par cet artiste - + + Sorry, we could not find any other albums for this artist! + Désolé, aucun autre album n'a pu être trouvé pour cet artiste ! + + + + Sorry, we could not find any tracks for this album! + Désolé, on a pas pu trouver aucune pistes pour cet album! + + + Other Albums by %1 - Autres albums par %1 + Autres albums de %1 AlbumModel - - Album - Album - - - - + + All albums from %1 Tous les albums de %1 - + All albums Tous les albums - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Après avoir scanné votre collection musicale, vous trouverez les derniers albums ajoutés ici. - - - - This collection doesn't have any recent albums. - Cette collection n'a pas d'albums récents - - ArtistInfoWidget @@ -193,23 +185,20 @@ se connecter et streamer depuis chez vous ? Albums Albums - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Après avoir scanné votre collection musicale, vous trouverez tous vos titres ici. + + Sorry, we could not find any albums for this artist! + Désolé, on a pas pu trouver aucun album pour cet artiste! - - This collection is currently empty. - La collection est vide actuellement. + + Sorry, we could not find any related artists! + Désolé, on a rien trouvé par rapport a cet artite! - - Sorry, your filter '%1' did not match any results. - Désolé, votre filtre '%1' ne correspond à aucun résultat + + Sorry, we could not find any top hits for this artist! + Désolé, on a pas pu trouver aucun top hit pour cet artiste! @@ -294,22 +283,25 @@ se connecter et streamer depuis chez vous ? CategoryAddItem - - New Playlist - Nouvelle liste de lecture + Create new Playlist + Créer une nouvelle liste de lecture - - - - + + Create new Station + Créer une nouvelle station + + + + + New Station Nouvelle Station - - - + + + %1 Station Station %1 @@ -335,27 +327,6 @@ se connecter et streamer depuis chez vous ? Vider - - CollectionFlatModel - - - My Collection - Ma Collection - - - - Collection of %1 - Collection de %1 - - - - CollectionView - - - This collection is empty. - La collection est vide. - - ContextWidget @@ -365,12 +336,12 @@ se connecter et streamer depuis chez vous ? - + Show Footnotes Afficher les notes - + Hide Footnotes Masquer les notes @@ -385,7 +356,7 @@ se connecter et streamer depuis chez vous ? <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p><span style=" font-weight:600;">Désolé !</span>&nbsp;Tomahawk a planté. Dites-nous ce qui ne va pas ! Tomahawk a créé un rapport d'erreur qui sera utile pour améliorer la stabilité des prochaines versions. Vous pouvez dès maintenant envoyer ce rapport aux développeurs de Tomahawk.</p></body></html> @@ -426,7 +397,7 @@ se connecter et streamer depuis chez vous ? Failed to send crash info. - Échec de l'envoi des informations de plantage + Échec de l'envoi des informations de plantage. @@ -463,12 +434,7 @@ se connecter et streamer depuis chez vous ? Diagnostics de Tomahawk - - Update - Mettre à jour - - - + Copy to Clipboard Copier dans le presse papier @@ -548,7 +514,7 @@ se connecter et streamer depuis chez vous ? %1 is listening along to you! - %1 écoute avec vous + %1 écoute avec vous! @@ -610,7 +576,7 @@ se connecter et streamer depuis chez vous ? Enter a title for the new playlist: - Entrer un titre pour la nouvelle liste de lecture + Entrer un titre pour la nouvelle liste de lecture: @@ -644,65 +610,71 @@ se connecter et streamer depuis chez vous ? PlayableModel - + Artist Artiste - + Title Titre - + Composer Compositeur - + Album Album - + Track Piste - + Duration Durée - + Bitrate Bitrate - + Age Age - + Year Année - + Size Taille - + Origin Origine - + Score Score + + + + Name + Nom + PlaylistItemDelegate @@ -748,12 +720,12 @@ se connecter et streamer depuis chez vous ? vous - + All tracks by %1 on album %2 Tous les titres de %1 sur l'album %2 - + All tracks by %1 Tous les titres de %1 @@ -773,7 +745,7 @@ se connecter et streamer depuis chez vous ? Don't know exactly what you want? Give Tomahawk a few pointers and let it build a playlist for you! - Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous. + Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous! @@ -799,7 +771,12 @@ se connecter et streamer depuis chez vous ? PlaylistView - + + This playlist is currently empty. + La collection est vide actuellement. + + + This playlist is currently empty. Add some tracks to it and enjoy the music! La liste de lecture est vide. Ajoutez des pistes et profitez de la musique ! @@ -964,14 +941,24 @@ se connecter et streamer depuis chez vous ? - - Show Queue - Afficher la file d'attente + + Open Queue + Ouvrir la file d'attente - - Hide Queue - Masquer la file d'attente + + The queue is currently empty. Drop something to enqueue it! + Le queue est vide actuellement. Laisse tomber quelque chose pour l'ajouter! + + + + Open Queue - %n item(s) + Ouvrir la file d'attente - %n élémentOuvrir la file d'attente - %n éléments + + + + Close Queue + Fermer la file d'attente @@ -1188,17 +1175,17 @@ se connecter et streamer depuis chez vous ? Dernières titres joués - + New Additions Nouveaux ajouts - + My recent activity Mon activité récente - + Recent activity from %1 Activité récente de %1 @@ -1206,31 +1193,36 @@ se connecter et streamer depuis chez vous ? SourceItem - + Collection Collection - + Latest Additions Derniers ajouts - + Recently Played Joués récemment - + Loved Tracks Titres favoris - + SuperCollection SuperCollection + + + Sorry, we could not find any loved tracks! + Désolé, on a pas pu trouver aucune piste favoris! + Latest additions to your collection @@ -1242,20 +1234,30 @@ se connecter et streamer depuis chez vous ? Derniers ajouts à la collection de %1 - + + Sorry, we could not find any recent additions! + Désolé, on a pas pu trouver des dernier ajouts! + + + Recently Played Tracks Derniers titres joués - + Your recently played tracks Les derniers titres que vous avez joués - + %1's recently played tracks Derniers titres joués par %1 + + + Sorry, we could not find any recent plays! + Désolé, on a pas pu trouver aucune piste récement joués! + SourceTreeView @@ -1272,17 +1274,17 @@ se connecter et streamer depuis chez vous ? Add to my Playlists - + Ajoute a mes listes de lecture Add to my Automatic Playlists - + Ajoute a mes listes de lecture automatique Add to my Stations - + Ajoute a mes stations @@ -1292,36 +1294,37 @@ se connecter et streamer depuis chez vous ? playlist - + liste de lecture automatic playlist - + liste de lecture automatique station - + station Delete %1? playlist/station/... - + Supprimer %1? Would you like to delete the %1 <b>"%2"</b>? - + e.g. Would you like to delete the playlist named Foobar? + Voulez-vous supprimer la %1 <b>"%2"</b>? - + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -1642,7 +1645,7 @@ et des stations basés sur vos goûts. Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 - + Malheureusement, l'installation automatique de ce script de résolution n'est pas disponible ou a été désactivé sur votre plateforme.<br /><br />Utiliser "Installer depuis un fichier" ci-dessus et téléchargez le fichier pour votre distribution, ou compilez-le. D'autres instructions sont disponibles ici :<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1718,7 +1721,7 @@ et des stations basés sur vos goûts. Importing History... - Import de l'historique + Import de l'historique... @@ -1757,7 +1760,7 @@ et des stations basés sur vos goûts. Re-enable syncing with Spotify - + Réactiver la synchronisation avec Spotify @@ -1801,7 +1804,7 @@ et des stations basés sur vos goûts. Connect to your Twitter followers. - Se connecter à vos followers sur Twitter + Se connecter à vos followers sur Twitter. @@ -1977,7 +1980,7 @@ Essayez de vous authentifier de nouveau. Un-&Love - Supprimer des Favoris + &Supprimer des Favoris @@ -2018,32 +2021,32 @@ Essayez de vous authentifier de nouveau. Tomahawk::CustomPlaylistView - + Top Loved Tracks Top des titres favoris - + Your loved tracks Vos titres favoris - + %1's loved tracks Titres favoris de %1 - + The most loved tracks from all your friends Les titres favoris de vos amis - + All of your loved tracks Tous vos titres favoris - + All of %1's loved tracks Tous les titres favoris de %1 @@ -2053,22 +2056,22 @@ Essayez de vous authentifier de nouveau. playlist - + liste de lecture artist - + artiste track - + titre album - + album @@ -2123,17 +2126,17 @@ Veuillez changer les filtres et essayez de nouveau. Tomahawk::DynamicView - + Add some filters above to seed this station! Ajoutez des filtres ci dessus pour commencer une station ! - + Press Generate to get started! Appuyez sur Générer pour commencer ! - + Add some filters above, and press Generate to get started! Ajoutez des filtres ci dessus et appuyez sur "Générer" pour commencer ! @@ -2171,7 +2174,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings - Aucun utilisateur avec un Catalogue The Echo Nest actif. Essayez d'activer l'option dans les préférences de Collection. + Aucun utilisateur avec un Catalogue The Echo Nest actif. Essayez d'activer l'option dans les préférences de Collection @@ -2836,7 +2839,7 @@ saisissez le numéro PIN ici : Currently not playing. - Pas de lecture en cours + Pas de lecture en cours. @@ -2851,12 +2854,12 @@ saisissez le numéro PIN ici : &Love - + &Favori Un-&Love - + &Supprimer des Favoris @@ -2934,7 +2937,7 @@ saisissez le numéro PIN ici : Load &XSPF... - Charger &XSPF + Charger &XSPF... @@ -2944,12 +2947,12 @@ saisissez le numéro PIN ici : About &Tomahawk... - A propos de &Tomahawk + A propos de &Tomahawk... Create New &Automatic Playlist - Créer une nouvelle liste de lecture automatique + Créer une nouvelle liste de lecture &automatique @@ -3003,7 +3006,7 @@ saisissez le numéro PIN ici : - + Play Lecture @@ -3048,142 +3051,147 @@ saisissez le numéro PIN ici : Recherche Globale... - - + + Check For Updates... Rechercher une mise à jour... - - - + + + Connect To Peer Connexion à un pair - + Enter peer address: Adresse du pair : - + Enter peer port: Port du pair : - + Enter peer key: Clé du pair : - + XSPF Error Erreur XSPF - + This is not a valid XSPF playlist. Ceci n'est pas une liste de lecture XSPF valide. - + Failed to save tracks Échec de la sauvegarde des pistes - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. - + + Station + Station + + + Create New Station Créer une nouvelle station - + Name: Nom : - - New Station - Nouvelle station + + Playlist + Liste de lecture - - New Playlist - Nouvelle liste de lecture + + Automatic Playlist + Liste de lecture automatique - + Pause Pause - + Go &offline Se &déconnecter - + Go &online Se c&onnecter - + Authentication Error Erreur d'authentification - + Error connecting to SIP: Authentication failed! Erreur de connexion SIP : échec de l'authentification ! - + %1 by %2 track, artist name %1 par %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Droit d'auteur 2010 - 2012 - + Thanks to: - + Merci a: - + About Tomahawk A propos de Tomahawk @@ -3311,28 +3319,33 @@ saisissez le numéro PIN ici : Similar Tracks Piste similaire + + + Sorry, but we could not find similar tracks for this song! + Désolé, on a pas pu trouver aucune pistes pour cette chanson! + - + You've listened to this track %n time(s). Vous avez écouté cette piste %n fois.Vous avez écouté cette piste %n fois. - + You've never listened to this track before. Vous n'avez encore jamais écouté cette piste. - + You first listened to it on %1. Vous l'avez écouté pour la première fois le %1. - + You've listened to %1 %n time(s). Vous avez écouté %1 %n fois.Vous avez écouté %1 %n fois. - + You've never listened to %1 before. Vous n'avez encore jamais écouté %1. @@ -3340,9 +3353,9 @@ saisissez le numéro PIN ici : TrackView - + Sorry, your filter '%1' did not match any results. - Désolé, votre filtre '%1' ne correspond à aucun résultat + Désolé, votre filtre '%1' ne correspond à aucun résultat. @@ -3369,63 +3382,31 @@ saisissez le numéro PIN ici : TreeModel - - Name - Nom - - - - Duration - Durée - - - - Bitrate - Bitrate - - - - Age - Age - - - - Year - Année - - - - Size - Taille - - - - Origin - Origine - - - - Composer - Compositeur - - - + All Artists Tous les artistes - - + + My Collection Ma Collection - - + + Collection of %1 Collection de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + Désolé, votre filtre '%1' ne correspond à aucun résultat. + + TwitterConfigWidget @@ -3502,27 +3483,37 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env ViewManager - + + After you have scanned your music collection you will find your tracks right here. + Après avoir scanné votre collection musicale, vous trouverez tous vos titres ici. + + + + This collection is empty. + La collection est vide. + + + SuperCollection SuperCollection - + Combined libraries of all your online friends Collections regroupant toutes celles de vos amis en ligne - + All available albums Tous les albums disponibles - + Recently Played Tracks Derniers titres joués - + Recently played tracks from all your friends Derniers titres joués par vos amis @@ -3558,7 +3549,7 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env WhatsHotWidget - + Charts Charts @@ -3629,7 +3620,7 @@ Paroles de "%1" par %2 : Some playlist entries were found without artist and track name, they will be omitted - Certaines entrées de la liste de lecture n'ont pas d'artiste ou de titre, elles seront omises. + Certaines entrées de la liste de lecture n'ont pas d'artiste ou de titre, elles seront omises @@ -3844,7 +3835,7 @@ Paroles de "%1" par %2 : Unknown - Ajouter un &ami... + Inconnu @@ -3874,7 +3865,7 @@ Paroles de "%1" par %2 : Enter Xmpp ID: - Entrer l'ID XMPP + Entrer l'ID XMPP: diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index d6454b523..c29b529f4 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -133,7 +133,17 @@ connect and stream from you? 他のアルバム - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 %1の他のアルバム @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - アルバム - - - - + + All albums from %1 %1のすべてのアルバム - + All albums 全アルバム - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - コレクションをスキャンした後、最近追加したアルバムがここに表示されます。 - - - - This collection doesn't have any recent albums. - 最近追加したアルバムはありません。 - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums アルバム - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - コレクションをスキャンした後、最近追加したトラックがここに表示されます。 + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - このコレクションは現在空です。 + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - '%1'に一致する情報は見つかりませんでした。 + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - 新規プレイリスト + Create new Playlist + - - - - + + Create new Station + + + + + + New Station 新規ステーション - - - + + + %1 Station %1 ステーション @@ -334,27 +326,6 @@ connect and stream from you? クリアー - - CollectionFlatModel - - - My Collection - マイ コレクション - - - - Collection of %1 - %1のコレクション - - - - CollectionView - - - This collection is empty. - このコレクションは空です。 - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes 脚注を表示 - + Hide Footnotes 脚注を隠す @@ -462,12 +433,7 @@ connect and stream from you? Tomahawkの診断 - - Update - 更新 - - - + Copy to Clipboard クリップボードにコピーする @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + アーティスト - + Title - + Composer - + Album - + アルバム - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? あなた - + All tracks by %1 on album %2 %1のアルバム%2のトラック - + All tracks by %1 %1のトラック @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! プレイリストには何も入っていません。トラックを追加して、音楽を楽しみましょう! @@ -970,13 +947,23 @@ other: %n週間 - - Show Queue + + Open Queue - - Hide Queue + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue @@ -1194,17 +1181,17 @@ other: %n週間 - + New Additions - + My recent activity - + Recent activity from %1 @@ -1212,31 +1199,36 @@ other: %n週間 SourceItem - + Collection コレクション - + Latest Additions - + Recently Played - + Loved Tracks - + SuperCollection スーパーコレクション + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1248,20 +1240,30 @@ other: %n週間 - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1319,15 +1321,16 @@ other: %n週間 Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -1430,7 +1433,7 @@ other: %n週間 Log In - + ログイン @@ -1544,7 +1547,7 @@ other: %n週間 Set this to your external IP address or host name. Make sure to forward the port to this host! - + フォーム @@ -1773,12 +1776,12 @@ other: %n週間 Logging in... - + ログイン中... Logged in! - + ログインしました! @@ -1788,7 +1791,7 @@ other: %n週間 Log In - + ログイン @@ -2018,32 +2021,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -2053,22 +2056,22 @@ You may wish to try re-authenticating. playlist - + プレイリスト artist - + アーティスト track - + トラック album - + アルバム @@ -2110,7 +2113,7 @@ Please change the filters or try again. Type: - + 入力: @@ -2121,17 +2124,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2564,17 +2567,17 @@ Try tweaking the filters for a new set of songs to play. Artists - + アーティスト Albums - + アルバム Tracks - + トラック @@ -2623,7 +2626,7 @@ Try tweaking the filters for a new set of songs to play. Albums - + アルバム @@ -2899,7 +2902,7 @@ enter the displayed PIN number here: Ctrl+Q - + Ctrl+Q @@ -2969,7 +2972,7 @@ enter the displayed PIN number here: Ctrl+M - + Ctrl+M @@ -2998,9 +3001,9 @@ enter the displayed PIN number here: - + Play - + 再生 @@ -3020,7 +3023,7 @@ enter the displayed PIN number here: Back - + プレイリスト @@ -3043,142 +3046,147 @@ enter the displayed PIN number here: - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station 新規ステーションを作成 - + Name: + 名前: + + + + Playlist + プレイリスト + + + + Automatic Playlist - - New Station - - - - - New Playlist - - - - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3188,7 +3196,7 @@ enter the displayed PIN number here: Form - + フォーム @@ -3289,7 +3297,7 @@ enter the displayed PIN number here: Album - + アルバム @@ -3299,35 +3307,40 @@ enter the displayed PIN number here: Lyrics - + 歌詞 Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3335,7 +3348,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3364,63 +3377,31 @@ enter the displayed PIN number here: TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - + すべてのアーティスト - - + + My Collection - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3492,27 +3473,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - - SuperCollection + + After you have scanned your music collection you will find your tracks right here. - - Combined libraries of all your online friends + + This collection is empty. + SuperCollection + + + + + Combined libraries of all your online friends + + + + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3548,7 +3539,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts @@ -3736,7 +3727,7 @@ Lyrics for "%1" by %2: Password: - + パスワード: @@ -3751,12 +3742,12 @@ Lyrics for "%1" by %2: Server: - + サーバー: Port: - + ポート: @@ -3887,7 +3878,7 @@ Lyrics for "%1" by %2: Form - + フォーム diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index c468c636e..81e6587cf 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -133,7 +133,17 @@ connect and stream from you? Inne albumy artysty - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Inne albumy %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 Wszystkie albumy %1 - + All albums Wszystkie albumy - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Po zeskanowaniu swojej kolekcji muzycznej w tym miejscu znajdziesz ostatnio dodane albumy. - - - - This collection doesn't have any recent albums. - Ta kolekcja nie zawiera żadnych nowo dodanych albumów. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Albumy - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Po zeskanowaniu swojej kolekcji muzycznej utwory znajdziesz w tym miejscu. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Ta kolekcja jest aktualnie pusta. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Przepraszamy, twój filtr '%1' nie pasuje do żadnych wyników. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nowa lista + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nowa stacja - - - + + + %1 Station Stacja %1 @@ -334,27 +326,6 @@ connect and stream from you? Wyczyść - - CollectionFlatModel - - - My Collection - Moja Kolekcja - - - - Collection of %1 - Kolekcja %1 - - - - CollectionView - - - This collection is empty. - Ta kolekcja jest pusta. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Pokaż przypisy - + Hide Footnotes Schowaj przypisy @@ -462,12 +433,7 @@ connect and stream from you? Diagnostyka Tomahawk - - Update - Aktualizuj - - - + Copy to Clipboard Skopiuj do schowka @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? Twoja - + All tracks by %1 on album %2 Wszystkie piosenki %1 z albumu %2 - + All tracks by %1 Wszystkie piosenki %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Ta lista jest aktualnie pusta. Dodaj do niej trochę piosenek i ciesz się muzyką! @@ -962,14 +939,24 @@ connect and stream from you? - - Show Queue - Pokaż Kolejkę + + Open Queue + - - Hide Queue - Ukryj Kolejkę + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1186,17 +1173,17 @@ connect and stream from you? Ostatnio Odtwarzane Utwory - + New Additions Nowo dodane - + My recent activity Moja ostatnia aktywność - + Recent activity from %1 Ostatnia aktywność %1 @@ -1204,31 +1191,36 @@ connect and stream from you? SourceItem - + Collection Kolekcja - + Latest Additions Ostatnio Dodane - + Recently Played Ostatnio Odtworzone - + Loved Tracks Ulubione Utwory - + SuperCollection Superkolekcja + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1240,20 +1232,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1311,15 +1313,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -2014,32 +2017,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Najbardziej Lubiane Utwory - + Your loved tracks Twoje ulubione utwory - + %1's loved tracks Ulubione utwory %1 - + The most loved tracks from all your friends Najbardziej lubiane utwory wszystkich twoich znajomych - + All of your loved tracks Wszystkie twoje ulubione utwory - + All of %1's loved tracks Wszystkie ulubione utwory %1 @@ -2119,17 +2122,17 @@ Proszę zmienić filtry lub spróbować ponownie. Tomahawk::DynamicView - + Add some filters above to seed this station! Dodaj powyżej trochę filtrów, a Tomahawk utworzy stację z podobną muzyką! - + Press Generate to get started! Naciśnij Generuj aby zacząć! - + Add some filters above, and press Generate to get started! Dodaj powyżej trochę filtrów i naciśnij Generuj aby zacząć! @@ -2997,7 +3000,7 @@ wprowadź pokazany numer PIN tutaj: - + Play Odtwarzaj @@ -3042,142 +3045,147 @@ wprowadź pokazany numer PIN tutaj: Globalne Wyszukiwanie... - - + + Check For Updates... Sprawdź uaktualnienia... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error Błąd XSPF - + This is not a valid XSPF playlist. To nie jest poprawna lista XSPF. - + Failed to save tracks Nie udało się zapisać utworów - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Niektóre utwory na liście nie zawierają artysty i tytułu. Zostaną one zignorowane. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Utwórz Nową Stację - + Name: Nazwa: - - New Station - Nowa stacja + + Playlist + - - New Playlist - Nowa Lista + + Automatic Playlist + - + Pause Pauza - + Go &offline Przejdź do trybu &offline - + Go &online Przejdź do trybu &online - + Authentication Error Błąd uwierzytelniania - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 wykonawcy %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3305,28 +3313,33 @@ wprowadź pokazany numer PIN tutaj: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3334,7 +3347,7 @@ wprowadź pokazany numer PIN tutaj: TrackView - + Sorry, your filter '%1' did not match any results. Przepraszamy, twój filtr '%1' nie dopasował żadnych wyników. @@ -3363,63 +3376,31 @@ wprowadź pokazany numer PIN tutaj: TreeModel - - Name - Nazwa - - - - Duration - Czas trwania - - - - Bitrate - Bitrate - - - - Age - Wiek - - - - Year - Rok - - - - Size - Rozmiar - - - - Origin - Pochodzenie - - - - Composer - Kompozytor - - - + All Artists Wszyscy Artyści - - + + My Collection Moja Kolekcja - - + + Collection of %1 Kolekcja %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3496,27 +3477,37 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection SuperKolekcja - + Combined libraries of all your online friends Połączone biblioteki wszystkich twoich znajomych online - + All available albums Wszystkie dostępne albumy - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3552,7 +3543,7 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl WhatsHotWidget - + Charts Listy przebojów diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 0b6128255..722e9ab29 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -133,7 +133,17 @@ connect and stream from you? Outros álbuns do artista - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Outros álbuns por %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Álbum - - - - + + All albums from %1 Todos os álbuns de %1 - + All albums Todos os álbuns - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Depois que você escanear a sua biblioteca musical você encontrará aqui o último álbum adicionado. - - - - This collection doesn't have any recent albums. - Essa biblioteca não tem nenhum álbum recente. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Álbuns - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Depois que você escanear a sua biblioteca musical você encontrará aqui as suas faixas. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Essa biblioteca está vazia. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Desculpe, o seu filtro '%1' não encontreou nenhum resultado. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Nova lista de reprodução + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Nova estação - - - + + + %1 Station %1 Estação @@ -334,27 +326,6 @@ connect and stream from you? Limpar - - CollectionFlatModel - - - My Collection - Minha biblioteca - - - - Collection of %1 - Biblioteca de %1 - - - - CollectionView - - - This collection is empty. - Essa biblioteca está vazia. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Mostrar rodapé - + Hide Footnotes Ocultar rodapé @@ -462,12 +433,7 @@ connect and stream from you? Diagnóstico do Tomahawk - - Update - Atualização - - - + Copy to Clipboard Copiar @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? você - + All tracks by %1 on album %2 Todas as faixas de %1 no álbum %2 - + All tracks by %1 Todas as faixas de %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reprodução está vazia. Adicione algumas faixas para disfrutar de uma música! @@ -962,14 +939,24 @@ connect and stream from you? - - Show Queue - Mostrar fila + + Open Queue + - - Hide Queue - Ocultar fila + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1186,17 +1173,17 @@ connect and stream from you? Faixas reproduzidas recentemente - + New Additions Novas adições - + My recent activity Minha atividade recentes - + Recent activity from %1 Atividade recente de %1 @@ -1204,31 +1191,36 @@ connect and stream from you? SourceItem - + Collection Biblioteca - + Latest Additions - + Recently Played - + Loved Tracks Faixas favoritas - + SuperCollection + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1240,20 +1232,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1311,15 +1313,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -2013,32 +2016,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Faixas favoritas - + Your loved tracks Suas faixas favoritas - + %1's loved tracks Faixas favoritas de %1 - + The most loved tracks from all your friends As faixas preferidas dos seus amigos - + All of your loved tracks Todas as suas faixas preferidas - + All of %1's loved tracks Todas as faixas preferidas de %1 @@ -2118,17 +2121,17 @@ Por favor, mude os filtros ou tente novamente. Tomahawk::DynamicView - + Add some filters above to seed this station! Adicione alguns filtros para alimentar essa estação! - + Press Generate to get started! Precione Criar para iniciar! - + Add some filters above, and press Generate to get started! Adicione alguns filtros acima e precione Criar para iniciar! @@ -2996,7 +2999,7 @@ colocar o número PIN mostrado aqui: - + Play Reporduzir @@ -3041,142 +3044,147 @@ colocar o número PIN mostrado aqui: Busca global... - - + + Check For Updates... Buscar atualizações... - - - + + + Connect To Peer Conectar-se ao par - + Enter peer address: Coloque o endereço do par: - + Enter peer port: Coloque a porta do par: - + Enter peer key: Coloque a chave do par: - + XSPF Error Erro de XSPF - + This is not a valid XSPF playlist. Esta não é uma lista de reprodução XSPF válida. - + Failed to save tracks Falha ao salvar faixas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algumas faixas da lista de reprodução não contem artista e título. Estas serão ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Criar uma nova estação - + Name: Nome: - - New Station - Nova estação + + Playlist + - - New Playlist - Nova lista de reprodução + + Automatic Playlist + - + Pause Pausar - + Go &offline Desc&onectar - + Go &online C&onectar - + Authentication Error Erro de autenticação - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Sobre o Tomahawk @@ -3304,28 +3312,33 @@ colocar o número PIN mostrado aqui: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3333,7 +3346,7 @@ colocar o número PIN mostrado aqui: TrackView - + Sorry, your filter '%1' did not match any results. Desculpe, o seu filtro '%1' não encontreou nenhum resultado. @@ -3362,63 +3375,31 @@ colocar o número PIN mostrado aqui: TreeModel - - Name - Nome - - - - Duration - Duração - - - - Bitrate - Taxa de bits - - - - Age - Idate - - - - Year - Ano - - - - Size - Tamanho - - - - Origin - Origem - - - - Composer - - - - + All Artists Todos artistas - - + + My Collection Minha biblioteca - - + + Collection of %1 Biblioteca de %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3495,27 +3476,37 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment ViewManager - - SuperCollection + + After you have scanned your music collection you will find your tracks right here. - - Combined libraries of all your online friends + + This collection is empty. + SuperCollection + + + + + Combined libraries of all your online friends + + + + All available albums Todos os álbuns disponíveis - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3551,7 +3542,7 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment WhatsHotWidget - + Charts Gráficos diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index d67ae2dda..53ffac671 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -134,7 +134,17 @@ connect and stream from you? Другие альбомы артиста - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Другие альбомы %1 @@ -142,35 +152,17 @@ connect and stream from you? AlbumModel - - Album - Альбом - - - - + + All albums from %1 Все альбомы %1 - + All albums Все альбомы - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - После сканирования вашей музыкальной коллекции вы найдете свой альбомы тут. - - - - This collection doesn't have any recent albums. - Эта коллекция не имеет последних альбомов. - - ArtistInfoWidget @@ -193,23 +185,20 @@ connect and stream from you? Albums Альбомы - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - После сканирования вашей музыкальной коллекции вы найдете свои песни тут. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Коллекция пуста. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - К сожалению, '%1' фильтр не найдено ни одного результата. + + Sorry, we could not find any top hits for this artist! + @@ -294,22 +283,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Новый плейлист + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Новая станция - - - + + + %1 Station %1 Станция @@ -335,27 +327,6 @@ connect and stream from you? Очистить - - CollectionFlatModel - - - My Collection - Моя Коллекция - - - - Collection of %1 - Коллекция %1 - - - - CollectionView - - - This collection is empty. - Коллекция пуста. - - ContextWidget @@ -365,12 +336,12 @@ connect and stream from you? - + Show Footnotes Показать Информацию об Исполнителе - + Hide Footnotes Спрятать Информацию об Исполнителе @@ -463,12 +434,7 @@ connect and stream from you? Диагностика - - Update - Обновить - - - + Copy to Clipboard Сохранить в буфер обмена @@ -644,65 +610,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -748,12 +720,12 @@ connect and stream from you? Вы - + All tracks by %1 on album %2 Все песни %1 альбома %2 - + All tracks by %1 Все песни %1 @@ -799,7 +771,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Этот плейлист пустой. Добавьте какие-нибудь треки и наслаждайтесь музыкой! @@ -964,14 +941,24 @@ connect and stream from you? - - Show Queue - Показать Очередь + + Open Queue + - - Hide Queue - Скрыть Очередь + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1188,17 +1175,17 @@ connect and stream from you? Последние проигрыные песни - + New Additions Последние добавленые - + My recent activity Моя последняя активность - + Recent activity from %1 Последняя активно %1 @@ -1206,31 +1193,36 @@ connect and stream from you? SourceItem - + Collection Коллекция - + Latest Additions Последние добавленные - + Recently Played Последние воспроизводимые - + Loved Tracks Любимые песни - + SuperCollection Общая коллекция + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1242,20 +1234,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1313,15 +1315,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -2015,32 +2018,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Топ любимых песен - + Your loved tracks Ваши любимые песни - + %1's loved tracks %1's любимая песня - + The most loved tracks from all your friends Самые любимые песни от всех ваших друзей - + All of your loved tracks Все любимые песни - + All of %1's loved tracks Все от %1 любимые песни @@ -2120,17 +2123,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! Добавить некоторые фильтры, чтобы увидеть эту станцию​​! - + Press Generate to get started! Нажмите кнопку Создать, чтобы начать! - + Add some filters above, and press Generate to get started! Добавьте несколько фильтров выше, а затем нажмите Создать, чтобы начать! @@ -2997,7 +3000,7 @@ enter the displayed PIN number here: - + Play Играть @@ -3042,142 +3045,147 @@ enter the displayed PIN number here: Глобальный поиск - - + + Check For Updates... Проверить обновления... - - - + + + Connect To Peer Связаться с Peer - + Enter peer address: Введите адрес узла: - + Enter peer port: Введите адрес порта: - + Enter peer key: Введите адрес ключа: - + XSPF Error Ошибка XSPF - + This is not a valid XSPF playlist. Это не является допустимым XSPF плейлистом. - + Failed to save tracks Не удалось сохранить песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Некоторые треки в плейлисте не содержат исполнителя и название. Они будут проигнорированы. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Создать новую станцию - + Name: Имя: - - New Station - Новая станция + + Playlist + - - New Playlist - Новый плейлист + + Automatic Playlist + - + Pause Пауза - + Go &offline Отключиться - + Go &online Подлючиться - + Authentication Error Ошибка авторизации - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk О Tomahawk @@ -3305,28 +3313,33 @@ enter the displayed PIN number here: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3334,7 +3347,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Ваш поиск '%1' недал результатов. @@ -3363,63 +3376,31 @@ enter the displayed PIN number here: TreeModel - - Name - Имя - - - - Duration - Длительность - - - - Bitrate - Битрей - - - - Age - Возраст - - - - Year - Год - - - - Size - Размер - - - - Origin - Расположение - - - - Composer - Композитор - - - + All Artists Все исполнители - - + + My Collection Моя коллекция - - + + Collection of %1 Коллекция из %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3495,27 +3476,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection Общая коллекция - + Combined libraries of all your online friends Комбинированные библиотек всех ваших друзей онлайн - + All available albums Доступные альбомы - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3551,7 +3542,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Чарты diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 19cd6281e..6d464853f 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -133,7 +133,17 @@ connect and stream from you? Andra album av artisten - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Andra album av %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Album - - - - + + All albums from %1 Alla album från %1 - + All albums Alla album - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda album här. - - - - This collection doesn't have any recent albums. - Den här samlingen inga nya album. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Album - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Efter att du har scannat din musiksamling kommer du finna dina senaste tillagda låtar här. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Denna samling är tom. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Tyvärr, ditt filter "%1" matchade inte några resultat. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Ny spellista + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Ny station - - - + + + %1 Station %1 station @@ -334,27 +326,6 @@ connect and stream from you? Töm - - CollectionFlatModel - - - My Collection - Min samling - - - - Collection of %1 - Samling av %1 - - - - CollectionView - - - This collection is empty. - Denna samling är tom. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Visa fotnot - + Hide Footnotes Dölj fotnot @@ -462,12 +433,7 @@ connect and stream from you? Diagnostik för Tomahawk - - Update - Uppdatera - - - + Copy to Clipboard Kopiera till urklipp @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? dig - + All tracks by %1 on album %2 Alla spår av %1 från albumet %2 - + All tracks by %1 Alla spår av %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! Denna spellista är för närvarande tom. Lägg till några spår och njut av musiken! @@ -963,14 +940,24 @@ connect and stream from you? - - Show Queue - Visa kö + + Open Queue + - - Hide Queue - Dölj kö + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1187,17 +1174,17 @@ connect and stream from you? Senaste spelade spår - + New Additions Nya tillägg - + My recent activity Min senaste aktivitet - + Recent activity from %1 Senaste aktivitet från %1 @@ -1205,31 +1192,36 @@ connect and stream from you? SourceItem - + Collection Samling - + Latest Additions Senast tillagda - + Recently Played Senast spelade spår - + Loved Tracks Älskade låtar - + SuperCollection SuperCollection + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1241,20 +1233,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1312,15 +1314,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -2011,32 +2014,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks Mest älskade spår - + Your loved tracks Dina älskade spår - + %1's loved tracks Älskade spår för %1 - + The most loved tracks from all your friends De mest älskade spåren från alla dina vänner - + All of your loved tracks Alla dina älskade spår - + All of %1's loved tracks Alla spår som %1 älskar @@ -2114,17 +2117,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2991,7 +2994,7 @@ enter the displayed PIN number here: - + Play Spela upp @@ -3036,142 +3039,147 @@ enter the displayed PIN number here: Global sökning... - - + + Check For Updates... Leta efter uppdateringar... - - - + + + Connect To Peer Anslut till klient - + Enter peer address: Ange klientadress: - + Enter peer port: Ange klientport: - + Enter peer key: Ange klientnyckel: - + XSPF Error XSPF-fel - + This is not a valid XSPF playlist. Detta är inte en giltig XSPF-spellista. - + Failed to save tracks Misslyckades med att spara spår - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Några spår i spellistan innehåller inte någon artist och titel. De kommer att ignoreras. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station Skapa ny station - + Name: Namn: - - New Station - Ny station + + Playlist + - - New Playlist - Ny spellista + + Automatic Playlist + - + Pause Paus - + Go &offline Koppla &från - + Go &online A&nslut - + Authentication Error Autentiseringsfel - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 av %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3299,28 +3307,33 @@ enter the displayed PIN number here: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3328,7 +3341,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. @@ -3357,63 +3370,31 @@ enter the displayed PIN number here: TreeModel - - Name - Namn - - - - Duration - Speltid - - - - Bitrate - Bitfrekvens - - - - Age - Ålder - - - - Year - År - - - - Size - Storlek - - - - Origin - Källa - - - - Composer - - - - + All Artists Alla artister - - + + My Collection Min samling - - + + Collection of %1 Samling av %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3485,27 +3466,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - - SuperCollection + + After you have scanned your music collection you will find your tracks right here. - - Combined libraries of all your online friends + + This collection is empty. + SuperCollection + + + + + Combined libraries of all your online friends + + + + All available albums Alla tillgängliga album - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3541,7 +3532,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts Topplistor diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index b8e578c3a..82e608f6b 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -133,7 +133,17 @@ connect and stream from you? Sanatçının Diğer Albümleri - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 Diğer %1 Albümleri @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - Albüm - - - - + + All albums from %1 Bütün %1 albümleri - + All albums Bütün albümler - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - Müzik koleksiyonunuzu taradıktan sonra en son eklenen albümleri burada bulacaksınız. - - - - This collection doesn't have any recent albums. - Bu koleksiyonda en son eklenen bir albüm yok. - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums Albümler - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - Müzik koleksiyonunuzu taradıktan parçalarınız tam burada bulacaksınız. + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - Bu koleksiyon şu anda boş. + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - Üzgünüm, '%1' filtresi hiçbir sonuç getirmedi. + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - Yeni Şarkı Listesi + Create new Playlist + - - - - + + Create new Station + + + + + + New Station Yeni İstasyon - - - + + + %1 Station %1 İstasyon @@ -334,27 +326,6 @@ connect and stream from you? Temizle - - CollectionFlatModel - - - My Collection - Koleksiyonum - - - - Collection of %1 - %1 Koleksiyonu - - - - CollectionView - - - This collection is empty. - Bu koleksiyon boş. - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes Dipnotları Göster - + Hide Footnotes Dipnotları Gizle @@ -462,12 +433,7 @@ connect and stream from you? Tomahawk Tanılama - - Update - Güncelle - - - + Copy to Clipboard Pano'ya Kopyala @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? - + All tracks by %1 on album %2 - + All tracks by %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -962,13 +939,23 @@ connect and stream from you? - - Show Queue + + Open Queue - - Hide Queue + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue @@ -1186,17 +1173,17 @@ connect and stream from you? - + New Additions - + My recent activity - + Recent activity from %1 @@ -1204,31 +1191,36 @@ connect and stream from you? SourceItem - + Collection - + Latest Additions - + Recently Played - + Loved Tracks - + SuperCollection + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1240,20 +1232,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1311,15 +1313,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? - - - - - Save XSPF + e.g. Would you like to delete the playlist named Foobar? + Save XSPF + + + + Playlists (*.xspf) @@ -2010,32 +2013,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -2113,17 +2116,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2990,7 +2993,7 @@ enter the displayed PIN number here: - + Play @@ -3035,142 +3038,147 @@ enter the displayed PIN number here: - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station - + Name: - - New Station + + Playlist - - New Playlist + + Automatic Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3298,28 +3306,33 @@ enter the displayed PIN number here: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3327,7 +3340,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3356,63 +3369,31 @@ enter the displayed PIN number here: TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - - + + My Collection - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3484,27 +3465,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - - SuperCollection + + After you have scanned your music collection you will find your tracks right here. - - Combined libraries of all your online friends + + This collection is empty. + SuperCollection + + + + + Combined libraries of all your online friends + + + + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3540,7 +3531,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index d9d82390b..75cb038bb 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -133,7 +133,17 @@ connect and stream from you? 艺人的其他专辑 - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 %1 的其他专辑 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - 专辑 - - - - + + All albums from %1 来自 %1 的所有专辑 - + All albums 所有专辑 - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - - - - - This collection doesn't have any recent albums. - - - ArtistInfoWidget @@ -192,23 +184,20 @@ connect and stream from you? Albums 专辑 - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. + + Sorry, we could not find any albums for this artist! - - This collection is currently empty. - 此收藏目前为空 + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. - 抱歉,你的过滤条件 '%1' 未匹配任何结果 + + Sorry, we could not find any top hits for this artist! + @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - 新播放列表 + Create new Playlist + - - - - + + Create new Station + + + + + + New Station 新电台 - - - + + + %1 Station %1 电台 @@ -334,27 +326,6 @@ connect and stream from you? - - CollectionFlatModel - - - My Collection - - - - - Collection of %1 - - - - - CollectionView - - - This collection is empty. - - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes 显示脚注 - + Hide Footnotes 隐藏脚注 @@ -462,12 +433,7 @@ connect and stream from you? Tomahawk 诊断信息 - - Update - 更新 - - - + Copy to Clipboard 复制到剪贴板 @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? - + All tracks by %1 on album %2 - + All tracks by %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -962,13 +939,23 @@ connect and stream from you? - - Show Queue + + Open Queue - - Hide Queue + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue @@ -1186,17 +1173,17 @@ connect and stream from you? - + New Additions - + My recent activity - + Recent activity from %1 @@ -1204,31 +1191,36 @@ connect and stream from you? SourceItem - + Collection - + Latest Additions - + Recently Played - + Loved Tracks - + SuperCollection + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1240,20 +1232,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1311,15 +1313,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? - - - - - Save XSPF + e.g. Would you like to delete the playlist named Foobar? + Save XSPF + + + + Playlists (*.xspf) @@ -2010,32 +2013,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -2113,17 +2116,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2990,7 +2993,7 @@ enter the displayed PIN number here: - + Play @@ -3035,142 +3038,147 @@ enter the displayed PIN number here: - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station - + Name: - - New Station + + Playlist - - New Playlist + + Automatic Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3298,28 +3306,33 @@ enter the displayed PIN number here: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3327,7 +3340,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3356,63 +3369,31 @@ enter the displayed PIN number here: TreeModel - - Name - - - - - Duration - - - - - Bitrate - - - - - Age - - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - - + + My Collection - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3484,27 +3465,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - - SuperCollection + + After you have scanned your music collection you will find your tracks right here. - - Combined libraries of all your online friends + + This collection is empty. + SuperCollection + + + + + Combined libraries of all your online friends + + + + All available albums - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3540,7 +3531,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 60c611f11..96db3de83 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -133,7 +133,17 @@ connect and stream from you? 列出演出者的其他專輯 - + + Sorry, we could not find any other albums for this artist! + + + + + Sorry, we could not find any tracks for this album! + + + + Other Albums by %1 列出所有其他專輯,依 %1 @@ -141,35 +151,17 @@ connect and stream from you? AlbumModel - - Album - 專輯 - - - - + + All albums from %1 從 %1 的所有專輯 - + All albums 所有專輯 - - AlbumView - - - After you have scanned your music collection you will find your latest album additions right here. - 當您掃描您的音樂收藏,您會發現您的最新專輯添加在這裡。 - - - - This collection doesn't have any recent albums. - 這個收藏沒有任何最新專輯。 - - ArtistInfoWidget @@ -192,22 +184,19 @@ connect and stream from you? Albums 專輯 - - - ArtistView - - After you have scanned your music collection you will find your tracks right here. - 當您掃描您的音樂收藏,您將在這裡找到您的曲目。 + + Sorry, we could not find any albums for this artist! + - - This collection is currently empty. - 目前這個收藏是空的。 + + Sorry, we could not find any related artists! + - - Sorry, your filter '%1' did not match any results. + + Sorry, we could not find any top hits for this artist! @@ -293,22 +282,25 @@ connect and stream from you? CategoryAddItem - - New Playlist - 新增播放清單 + Create new Playlist + - - - - + + Create new Station + + + + + + New Station - - - + + + %1 Station @@ -334,27 +326,6 @@ connect and stream from you? 清除 - - CollectionFlatModel - - - My Collection - 我的收藏 - - - - Collection of %1 - - - - - CollectionView - - - This collection is empty. - 這個收藏是空的。 - - ContextWidget @@ -364,12 +335,12 @@ connect and stream from you? - + Show Footnotes 顯示註腳 - + Hide Footnotes 隱藏註腳 @@ -462,12 +433,7 @@ connect and stream from you? Tomahawk 診斷 - - Update - 更新 - - - + Copy to Clipboard 複製到剪貼簿 @@ -643,65 +609,71 @@ connect and stream from you? PlayableModel - + Artist - + Title - + Composer - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + + Name + + PlaylistItemDelegate @@ -747,12 +719,12 @@ connect and stream from you? - + All tracks by %1 on album %2 - + All tracks by %1 @@ -798,7 +770,12 @@ connect and stream from you? PlaylistView - + + This playlist is currently empty. + + + + This playlist is currently empty. Add some tracks to it and enjoy the music! 目前這個播放清單是空的。請加入一些曲目,然後盡情享受音樂! @@ -962,14 +939,24 @@ connect and stream from you? - - Show Queue - 顯示佇列 + + Open Queue + - - Hide Queue - 隱藏佇列 + + The queue is currently empty. Drop something to enqueue it! + + + + + Open Queue - %n item(s) + + + + + Close Queue + @@ -1186,17 +1173,17 @@ connect and stream from you? 最近播放的曲目 - + New Additions 新增 - + My recent activity 我的近期活動 - + Recent activity from %1 @@ -1204,31 +1191,36 @@ connect and stream from you? SourceItem - + Collection 收藏 - + Latest Additions 最新加入 - + Recently Played 最近播放的 - + Loved Tracks - + SuperCollection 超級收藏 + + + Sorry, we could not find any loved tracks! + + Latest additions to your collection @@ -1240,20 +1232,30 @@ connect and stream from you? - + + Sorry, we could not find any recent additions! + + + + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks + + + Sorry, we could not find any recent plays! + + SourceTreeView @@ -1311,15 +1313,16 @@ connect and stream from you? Would you like to delete the %1 <b>"%2"</b>? + e.g. Would you like to delete the playlist named Foobar? - + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -2010,32 +2013,32 @@ You may wish to try re-authenticating. Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends 在您所有的朋友中,最受喜愛的曲目 - + All of your loved tracks - + All of %1's loved tracks @@ -2113,17 +2116,17 @@ Please change the filters or try again. Tomahawk::DynamicView - + Add some filters above to seed this station! - + Press Generate to get started! - + Add some filters above, and press Generate to get started! @@ -2990,7 +2993,7 @@ enter the displayed PIN number here: - + Play 播放 @@ -3035,142 +3038,147 @@ enter the displayed PIN number here: 全域搜尋... - - + + Check For Updates... 檢查更新... - - - + + + Connect To Peer 連接點對點 - + Enter peer address: 輸入對等地址: - + Enter peer port: 輸入對等連接埠: - + Enter peer key: 輸入對等密鑰: - + XSPF Error XSPF 錯誤 - + This is not a valid XSPF playlist. - + Failed to save tracks 無法儲存曲目 - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + + Station + + + + Create New Station - + Name: 名稱: - - New Station + + Playlist - - New Playlist - 新增播放清單 + + Automatic Playlist + - + Pause 暫停 - + Go &offline 離線 - + Go &online 上網 - + Authentication Error 驗證錯誤 - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3298,28 +3306,33 @@ enter the displayed PIN number here: Similar Tracks + + + Sorry, but we could not find similar tracks for this song! + + - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3327,7 +3340,7 @@ enter the displayed PIN number here: TrackView - + Sorry, your filter '%1' did not match any results. @@ -3356,64 +3369,31 @@ enter the displayed PIN number here: TreeModel - - Name - 名稱 - - - - Duration - 長度 - - - - - Bitrate - - - - - Age - 年代 - - - - Year - - - - - Size - - - - - Origin - - - - - Composer - - - - + All Artists - - + + My Collection 我的收藏 - - + + Collection of %1 + + TreeView + + + Sorry, your filter '%1' did not match any results. + + + TwitterConfigWidget @@ -3485,27 +3465,37 @@ You can re-send a sync message at any time simply by sending another tweet using ViewManager - + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is empty. + + + + SuperCollection 超級收藏 - + Combined libraries of all your online friends 聯合您所有線上朋友的音樂庫 - + All available albums 所有現有專輯 - + Recently Played Tracks - + Recently played tracks from all your friends @@ -3541,7 +3531,7 @@ You can re-send a sync message at any time simply by sending another tweet using WhatsHotWidget - + Charts From 2425ec34e51563b2baefc18ce70ad8903ba6112e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 3 Jun 2012 15:38:36 +0200 Subject: [PATCH 265/433] * Use a separate database connection for each db-worker thread. --- src/libtomahawk/database/Database.cpp | 11 +-- src/libtomahawk/database/Database.h | 7 +- src/libtomahawk/database/DatabaseImpl.cpp | 74 +++++++++++++++------ src/libtomahawk/database/DatabaseImpl.h | 11 ++- src/libtomahawk/database/DatabaseWorker.cpp | 6 +- src/libtomahawk/database/DatabaseWorker.h | 3 +- 6 files changed, 76 insertions(+), 36 deletions(-) diff --git a/src/libtomahawk/database/Database.cpp b/src/libtomahawk/database/Database.cpp index 8c7199092..eea51aca0 100644 --- a/src/libtomahawk/database/Database.cpp +++ b/src/libtomahawk/database/Database.cpp @@ -26,12 +26,7 @@ #include "Source.h" #define DEFAULT_WORKER_THREADS 4 - -#if ( QT_VERSION >= QT_VERSION_CHECK(4, 8, 2) ) - #define MAX_WORKER_THREADS 1 -#else - #define MAX_WORKER_THREADS 16 -#endif +#define MAX_WORKER_THREADS 16 Database* Database::s_instance = 0; @@ -47,7 +42,7 @@ Database::Database( const QString& dbname, QObject* parent ) : QObject( parent ) , m_ready( false ) , m_impl( new DatabaseImpl( dbname, this ) ) - , m_workerRW( new DatabaseWorker( m_impl, this, true ) ) + , m_workerRW( new DatabaseWorker( this, true ) ) { s_instance = this; @@ -105,7 +100,7 @@ Database::enqueue( const QSharedPointer& lc ) // create new thread if < WORKER_THREADS if ( m_workers.count() < m_maxConcurrentThreads ) { - DatabaseWorker* worker = new DatabaseWorker( m_impl, this, false ); + DatabaseWorker* worker = new DatabaseWorker( this, false ); worker->start(); m_workers << worker; diff --git a/src/libtomahawk/database/Database.h b/src/libtomahawk/database/Database.h index b265bd39c..7bf05a09e 100644 --- a/src/libtomahawk/database/Database.h +++ b/src/libtomahawk/database/Database.h @@ -53,12 +53,13 @@ public: ~Database(); QString dbid() const; - bool indexReady() const { return m_indexReady; } void loadIndex(); - + bool indexReady() const { return m_indexReady; } bool isReady() const { return m_ready; } + DatabaseImpl* impl() const { return m_impl; } + signals: void indexReady(); // search index void ready(); @@ -74,8 +75,6 @@ private slots: void setIsReadyTrue() { m_ready = true; } private: - DatabaseImpl* impl() const { return m_impl; } - bool m_ready; DatabaseImpl* m_impl; DatabaseWorker* m_workerRW; diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 3c13d975e..60c34f9ae 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -46,9 +46,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) : QObject( (QObject*) parent ) - , m_lastartid( 0 ) - , m_lastalbid( 0 ) - , m_lasttrkid( 0 ) + , m_parent( parent ) { QTime t; t.start(); @@ -67,13 +65,10 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) m_dbid = uuid(); query.exec( QString( "INSERT INTO settings(k,v) VALUES('dbid','%1')" ).arg( m_dbid ) ); } - tLog() << "Database ID:" << m_dbid; - // make sqlite behave how we want: - query.exec( "PRAGMA auto_vacuum = FULL" ); - query.exec( "PRAGMA synchronous = ON" ); - query.exec( "PRAGMA foreign_keys = ON" ); - //query.exec( "PRAGMA temp_store = MEMORY" ); + tLog() << "Database ID:" << m_dbid; + init(); + tDebug( LOGVERBOSE ) << "Tweaked db pragmas:" << t.elapsed(); // in case of unclean shutdown last time: @@ -84,7 +79,6 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); tDebug( LOGVERBOSE ) << "Loaded index:" << t.elapsed(); - if ( qApp->arguments().contains( "--dumpdb" ) ) { dumpDatabase(); @@ -93,6 +87,30 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) } +DatabaseImpl::DatabaseImpl( Database* parent, const QString& dbname ) + : QObject( (QObject*) QThread::currentThread() ) + , m_parent( parent ) +{ + openDatabase( dbname, false ); + init(); +} + + +void +DatabaseImpl::init() +{ + m_lastartid = m_lastalbid = m_lasttrkid = 0; + + TomahawkSqlQuery query = newquery(); + + // make sqlite behave how we want: + query.exec( "PRAGMA auto_vacuum = FULL" ); + query.exec( "PRAGMA synchronous = ON" ); + query.exec( "PRAGMA foreign_keys = ON" ); + //query.exec( "PRAGMA temp_store = MEMORY" ); +} + + DatabaseImpl::~DatabaseImpl() { delete m_fuzzyIndex; @@ -115,6 +133,16 @@ DatabaseImpl::~DatabaseImpl() } +DatabaseImpl* +DatabaseImpl::clone() const +{ + DatabaseImpl* impl = new DatabaseImpl( m_parent, m_db.databaseName() ); + impl->setDatabaseID( m_dbid ); + impl->setFuzzyIndex( m_fuzzyIndex ); + return impl; +} + + void DatabaseImpl::dumpDatabase() { @@ -681,27 +709,35 @@ DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery ) bool -DatabaseImpl::openDatabase( const QString& dbname ) +DatabaseImpl::openDatabase( const QString& dbname, bool checkSchema ) { + const QStringList conns = QSqlDatabase::connectionNames(); + const QString connName = QString( "tomahawk%1" ).arg( conns.count() ? QString::number( conns.count() ) : "" ); + bool schemaUpdated = false; int version = -1; { - QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" ); + QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", connName ); db.setDatabaseName( dbname ); if ( !db.open() ) { tLog() << "Failed to open database" << dbname; throw "failed to open db"; // TODO } - - QSqlQuery qry = QSqlQuery( db ); - qry.exec( "SELECT v FROM settings WHERE k='schema_version'" ); - if ( qry.next() ) + + if ( checkSchema ) { - version = qry.value( 0 ).toInt(); - tLog() << "Database schema of" << dbname << "is" << version; + QSqlQuery qry = QSqlQuery( db ); + qry.exec( "SELECT v FROM settings WHERE k='schema_version'" ); + if ( qry.next() ) + { + version = qry.value( 0 ).toInt(); + tLog() << "Database schema of" << dbname << "is" << version; + } } - + else + version = CURRENT_SCHEMA_VERSION; + if ( version < 0 || version == CURRENT_SCHEMA_VERSION ) m_db = db; } diff --git a/src/libtomahawk/database/DatabaseImpl.h b/src/libtomahawk/database/DatabaseImpl.h index f734f171f..671c86018 100644 --- a/src/libtomahawk/database/DatabaseImpl.h +++ b/src/libtomahawk/database/DatabaseImpl.h @@ -48,7 +48,7 @@ public: DatabaseImpl( const QString& dbname, Database* parent = 0 ); ~DatabaseImpl(); - bool openDatabase( const QString& dbname ); + DatabaseImpl* clone() const; TomahawkSqlQuery newquery() { return TomahawkSqlQuery( m_db ); } QSqlDatabase& database() { return m_db; } @@ -85,10 +85,17 @@ private slots: void updateIndex(); private: - QString cleanSql( const QString& sql ); + DatabaseImpl( Database* parent, const QString& dbname ); + void setFuzzyIndex( FuzzyIndex* fi ) { m_fuzzyIndex = fi; } + void setDatabaseID( const QString& dbid ) { m_dbid = dbid; } + + void init(); + bool openDatabase( const QString& dbname, bool checkSchema = true ); bool updateSchema( int oldVersion ); void dumpDatabase(); + QString cleanSql( const QString& sql ); + Database* m_parent; bool m_ready; QSqlDatabase m_db; diff --git a/src/libtomahawk/database/DatabaseWorker.cpp b/src/libtomahawk/database/DatabaseWorker.cpp index bf4972fb0..30481bde3 100644 --- a/src/libtomahawk/database/DatabaseWorker.cpp +++ b/src/libtomahawk/database/DatabaseWorker.cpp @@ -34,9 +34,9 @@ //#define DEBUG_TIMING TRUE #endif -DatabaseWorker::DatabaseWorker( DatabaseImpl* lib, Database* db, bool mutates ) +DatabaseWorker::DatabaseWorker( Database* db, bool mutates ) : QThread() - , m_dbimpl( lib ) + , m_db( db ) , m_outstanding( 0 ) { Q_UNUSED( db ); @@ -68,6 +68,8 @@ DatabaseWorker::~DatabaseWorker() void DatabaseWorker::run() { + m_dbimpl = m_db->impl()->clone(); + tDebug() << "New db connection with name:" << m_dbimpl->database().connectionName(); exec(); qDebug() << Q_FUNC_INFO << "DatabaseWorker finishing..."; } diff --git a/src/libtomahawk/database/DatabaseWorker.h b/src/libtomahawk/database/DatabaseWorker.h index 458d4d427..7da0acc6c 100644 --- a/src/libtomahawk/database/DatabaseWorker.h +++ b/src/libtomahawk/database/DatabaseWorker.h @@ -39,7 +39,7 @@ class DatabaseWorker : public QThread Q_OBJECT public: - DatabaseWorker( DatabaseImpl*, Database*, bool mutates ); + DatabaseWorker( Database*, bool mutates ); ~DatabaseWorker(); bool busy() const { return m_outstanding > 0; } @@ -59,6 +59,7 @@ private: void logOp( DatabaseCommandLoggable* command ); QMutex m_mut; + Database* m_db; DatabaseImpl* m_dbimpl; QList< QSharedPointer > m_commands; int m_outstanding; From 2fefdf8118c718a1daa88239f8be6de67475fda9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 3 Jun 2012 21:22:56 +0200 Subject: [PATCH 266/433] * Move query to the top of the pipeline if a secondary, prioritized resolve requests arrives. --- src/libtomahawk/Pipeline.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index 5966ad7be..8fb42a00b 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -201,14 +201,20 @@ Pipeline::resolve( const QList& qlist, bool prioritized, bool tempora QMutexLocker lock( &m_mut ); int i = 0; - foreach( const query_ptr& q, qlist ) + foreach ( const query_ptr& q, qlist ) { if ( q->resolvingFinished() ) continue; - if ( m_queries_pending.contains( q ) ) - continue; if ( m_qidsState.contains( q->id() ) ) continue; + if ( m_queries_pending.contains( q ) ) + { + if ( prioritized ) + { + m_queries_pending.insert( i++, m_queries_pending.takeAt( m_queries_pending.indexOf( q ) ) ); + } + continue; + } if ( !m_qids.contains( q->id() ) ) m_qids.insert( q->id(), q ); @@ -266,7 +272,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) const query_ptr& q = m_qids.value( qid ); QList< result_ptr > cleanResults; - foreach( const result_ptr& r, results ) + foreach ( const result_ptr& r, results ) { float score = q->howSimilar( r ); r->setScore( score ); @@ -279,7 +285,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) if ( !cleanResults.isEmpty() ) { q->addResults( cleanResults ); - foreach( const result_ptr& r, cleanResults ) + foreach ( const result_ptr& r, cleanResults ) { m_rids.insert( r->id(), r ); } @@ -310,7 +316,7 @@ Pipeline::reportAlbums( QID qid, const QList< album_ptr >& albums ) Q_ASSERT( q->isFullTextQuery() ); QList< album_ptr > cleanAlbums; - foreach( const album_ptr& r, albums ) + foreach ( const album_ptr& r, albums ) { // float score = q->howSimilar( r ); @@ -339,7 +345,7 @@ Pipeline::reportArtists( QID qid, const QList< artist_ptr >& artists ) Q_ASSERT( q->isFullTextQuery() ); QList< artist_ptr > cleanArtists; - foreach( const artist_ptr& r, artists ) + foreach ( const artist_ptr& r, artists ) { // float score = q->howSimilar( r ); From 2b3f850259c2b58a8cf145e70b332391490712f6 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 3 Jun 2012 21:23:36 +0200 Subject: [PATCH 267/433] * Prioritize query for resolving when requesting to play a still unresolved query. --- src/libtomahawk/audio/AudioEngine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 8fd3e798a..75f2748ee 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -36,6 +36,7 @@ #include "HeadlessCheck.h" #include "infosystem/InfoSystem.h" #include "Album.h" +#include "Pipeline.h" #include "utils/Logger.h" @@ -605,6 +606,8 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk: } else { + Pipeline::instance()->resolve( query ); + NewClosure( query.data(), SIGNAL( resolvingFinished( bool ) ), const_cast(this), SLOT( playItem( Tomahawk::playlistinterface_ptr, Tomahawk::query_ptr ) ), playlist, query ); } From fc5fa6d4ea4ad3f38bead2fe7adfdce540f0a2b9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 4 Jun 2012 21:07:12 +0200 Subject: [PATCH 268/433] * Don't manually delete the fuzzy index, instead rely on QObject parenting. --- src/libtomahawk/database/DatabaseImpl.cpp | 4 +--- src/libtomahawk/database/FuzzyIndex.cpp | 4 ++-- src/libtomahawk/database/FuzzyIndex.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 60c34f9ae..6ad747104 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -74,7 +74,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) // in case of unclean shutdown last time: query.exec( "UPDATE source SET isonline = 'false'" ); - m_fuzzyIndex = new FuzzyIndex( schemaUpdated ); + m_fuzzyIndex = new FuzzyIndex( this, schemaUpdated ); if ( schemaUpdated ) QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); @@ -113,8 +113,6 @@ DatabaseImpl::init() DatabaseImpl::~DatabaseImpl() { - delete m_fuzzyIndex; - tDebug() << "Shutting down database."; /* diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index 86334d5a0..a6a117ffc 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -38,8 +38,8 @@ using namespace lucene::queryParser; using namespace lucene::search; -FuzzyIndex::FuzzyIndex( bool wipeIndex ) - : QObject() +FuzzyIndex::FuzzyIndex( QObject* parent, bool wipeIndex ) + : QObject( parent ) , m_luceneReader( 0 ) , m_luceneSearcher( 0 ) { diff --git a/src/libtomahawk/database/FuzzyIndex.h b/src/libtomahawk/database/FuzzyIndex.h index 8a66b491b..f6da1aa76 100644 --- a/src/libtomahawk/database/FuzzyIndex.h +++ b/src/libtomahawk/database/FuzzyIndex.h @@ -55,7 +55,7 @@ class FuzzyIndex : public QObject Q_OBJECT public: - explicit FuzzyIndex( bool wipeIndex = false ); + explicit FuzzyIndex( QObject* parent, bool wipeIndex = false ); ~FuzzyIndex(); void beginIndexing(); From 722e1c3d577b1c0cf15b0798c1c39df93ffb6fa7 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Mon, 4 Jun 2012 16:34:19 -0400 Subject: [PATCH 269/433] Update logo for Tomahawklet Auth Page --- data/www/tomahawk_banner_small.png | Bin 6938 -> 27360 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/www/tomahawk_banner_small.png b/data/www/tomahawk_banner_small.png index 83a818d17cd247ff8ac68db51996547491880b11..67fc8b4cb77cdcd8a11bbf68323065b4fb862769 100644 GIT binary patch literal 27360 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 literal 6938 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 From a2082bbb44d429305de2d43e1b9644132a5cfa09 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Mon, 4 Jun 2012 16:42:58 -0400 Subject: [PATCH 270/433] More fixes on playdar auth page --- data/www/auth.html | 4 ++-- data/www/auth.na.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/www/auth.html b/data/www/auth.html index cdfba330d..49306f1bb 100644 --- a/data/www/auth.html +++ b/data/www/auth.html @@ -43,8 +43,8 @@ -
    - Tomahawk - Powered by Playdar + + Tomahawk - Powered by Playdar
    diff --git a/data/www/auth.na.html b/data/www/auth.na.html index d1b816572..4d3c122a5 100644 --- a/data/www/auth.na.html +++ b/data/www/auth.na.html @@ -32,8 +32,8 @@ - - Tomahawk - Powered by Playdar + + Tomahawk - Powered by Playdar
    From ff0d4bcc26d394986287569705ac7fadb4875900 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Mon, 4 Jun 2012 16:49:26 -0400 Subject: [PATCH 271/433] Now make logo appear on auth page again --- data/www/auth.html | 2 +- data/www/auth.na.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/www/auth.html b/data/www/auth.html index 49306f1bb..d1193ee5d 100644 --- a/data/www/auth.html +++ b/data/www/auth.html @@ -44,7 +44,7 @@ - Tomahawk - Powered by Playdar + Tomahawk - Powered by Playdar
    diff --git a/data/www/auth.na.html b/data/www/auth.na.html index 4d3c122a5..ee4463d5b 100644 --- a/data/www/auth.na.html +++ b/data/www/auth.na.html @@ -33,7 +33,7 @@ - Tomahawk - Powered by Playdar + Tomahawk - Powered by Playdar
    From 0401c4c88cf3f8d29dba77711efbe4e2f88754d4 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 30 May 2012 12:11:24 +0100 Subject: [PATCH 272/433] Another os x ui tweak --- .../playlist/dynamic/echonest/EchonestSteerer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp index 28b496649..82a44d3c0 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestSteerer.cpp @@ -68,7 +68,11 @@ EchonestSteerer::EchonestSteerer( QWidget* parent ) QPalette p = m_steerTop->palette(); - p.setBrush( QPalette::WindowText, palette().highlightedText() ); +#ifdef Q_OS_MAC + p.setBrush( QPalette::WindowText, Qt::white ); +#else + p.setBrush( QPalette::WindowText, palette().highlightedText() ); +#endif m_steerTop->setPalette( p ); m_layout->addLayout( m_textL, 1 ); From 8ba4cb66eaa7b4ccdbb89f23d25193e950c3081e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 5 Jun 2012 09:10:56 +0100 Subject: [PATCH 273/433] Declare method as well --- src/TomahawkApp.cpp | 2 +- src/libtomahawk/mac/FileHelpers.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index d95e24840..0b46c7f1e 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -328,7 +328,7 @@ TomahawkApp::init() connect( r, SIGNAL( finished() ), this, SLOT( spotifyApiCheckFinished() ) ); #endif -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC // Make sure to do this after main window is inited Tomahawk::enableFullscreen( m_mainwindow ); #endif diff --git a/src/libtomahawk/mac/FileHelpers.h b/src/libtomahawk/mac/FileHelpers.h index 5c0d46803..ad5fb49d0 100644 --- a/src/libtomahawk/mac/FileHelpers.h +++ b/src/libtomahawk/mac/FileHelpers.h @@ -33,6 +33,8 @@ // Will be asynchronous: Implement the delegate protocol know about the completion + (void) moveFile:(NSString *)source to:(NSString*)dest withDelegate:delegate; +// Internal ++ (void)notifyDelegate:(NSDictionary *)info; @end From a8ff291a37734af47d2b878b0ad5c666e6538995 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 5 Jun 2012 09:17:05 +0100 Subject: [PATCH 274/433] Faster pixmap fading --- src/libtomahawk/utils/PixmapDelegateFader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/utils/PixmapDelegateFader.cpp b/src/libtomahawk/utils/PixmapDelegateFader.cpp index 867a4d26a..b03e57f6d 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.cpp +++ b/src/libtomahawk/utils/PixmapDelegateFader.cpp @@ -186,11 +186,11 @@ PixmapDelegateFader::setPixmap( const QPixmap& pixmap ) return; m_defaultImage = false; - QByteArray ba; - QBuffer buffer( &ba ); - buffer.open( QIODevice::WriteOnly ); - pixmap.save( &buffer, "PNG" ); - QString newImageMd5 = TomahawkUtils::md5( buffer.data() ); + QCryptographicHash hash( QCryptographicHash::Md5 ); + const QImage img = pixmap.toImage(); + hash.addData( (const char*)img.constBits(), img.byteCount() ); + const QString newImageMd5 = hash.result(); + if ( m_oldImageMd5 == newImageMd5 ) return; From c001acffee6fa9ef59aad9d589b71f4445060090 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 5 Jun 2012 09:17:23 +0100 Subject: [PATCH 275/433] Don't leak --- src/libtomahawk/AtticaManager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index b3de882e6..099ca09c2 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -73,6 +73,15 @@ AtticaManager::AtticaManager( QObject* parent ) AtticaManager::~AtticaManager() { savePixmapsToCache(); + + + foreach( const QString& id, m_resolverStates.keys() ) + { + if ( !m_resolverStates[ id ].pixmap ) + continue; + + delete m_resolverStates[ id ].pixmap; + } } From 338a39fe5b2992a14ecec661cb311cf87dbb6196 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 5 Jun 2012 09:17:56 +0100 Subject: [PATCH 276/433] Attempt to make sizegrip fix work from 10.6 builds --- src/mac/TomahawkApp_Mac.mm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mac/TomahawkApp_Mac.mm b/src/mac/TomahawkApp_Mac.mm index 402fb4c7f..187981dcf 100644 --- a/src/mac/TomahawkApp_Mac.mm +++ b/src/mac/TomahawkApp_Mac.mm @@ -166,14 +166,14 @@ NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager]; [em setEventHandler:self - andSelector:@selector(getUrl:withReplyEvent:) - forEventClass:kInternetEventClass - andEventID:kAEGetURL]; + andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; [em setEventHandler:self - andSelector:@selector(getUrl:withReplyEvent:) - forEventClass:'WWW!' - andEventID:'OURL']; + andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:'WWW!' + andEventID:'OURL']; NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; OSStatus httpResult = LSSetDefaultHandlerForURLScheme((CFStringRef)@"tomahawk", (CFStringRef)bundleID); @@ -253,8 +253,10 @@ void Tomahawk::checkForUpdates() { #ifdef LION #define SET_LION_FULLSCREEN NSWindowCollectionBehaviorFullScreenPrimary +#define LION_FULLSCREEN_NOTIFICATION_VALUE NSWindowWillEnterFullScreenNotification #else #define SET_LION_FULLSCREEN (NSUInteger)(1 << 7) // Defined as NSWindowCollectionBehaviorFullScreenPrimary in lion's NSWindow.h +#define LION_FULLSCREEN_NOTIFICATION_VALUE @"NSWindowWillEnterFullScreenNotification" #endif void Tomahawk::enableFullscreen( QObject* receiver ) @@ -276,25 +278,23 @@ void Tomahawk::enableFullscreen( QObject* receiver ) NSWindow *nswindow = [nsview window]; [nswindow setCollectionBehavior:SET_LION_FULLSCREEN]; -#ifdef LION if ( !receiver ) continue; - [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillEnterFullScreenNotification + [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_NOTIFICATION_VALUE object:nswindow queue:nil usingBlock:^(NSNotification * note) { NSLog(@"Became Full Screen!"); QMetaObject::invokeMethod( receiver, "fullScreenEntered", Qt::DirectConnection ); }]; - [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidExitFullScreenNotification + [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_NOTIFICATION_VALUE object:nswindow queue:nil usingBlock:^(NSNotification * note) { NSLog(@"Left Full Screen!"); QMetaObject::invokeMethod( receiver, "fullScreenExited", Qt::DirectConnection ); }]; -#endif } } } From 89c0e71874d0ad19d685580687eb96b05a90b1b8 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Tue, 5 Jun 2012 22:17:07 +0000 Subject: [PATCH 277/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_bg.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_ca.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_de.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_en.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_es.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_fr.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_ja.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_pl.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_pt_BR.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_ru.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_sv.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_tr.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_zh_CN.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_zh_TW.ts | 36 ++++++++++++++++++------------------ 15 files changed, 270 insertions(+), 270 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index ac6733d95..30940d14f 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -2463,92 +2463,92 @@ Try tweaking the filters for a new set of songs to play. قد هذه الإذاعة: - + Much less أقل بكثير - + Less أقل - + A bit less أقل بقليل - + Keep at current أبقه على حاله - + A bit more أكثر قليلا - + More أكثر - + Much more أكثر من ذلك بكثير - + Tempo سرعة إيقاع - + Loudness قوة الصوت - + Danceability درجة الرقص - + Energy حيوية - + Song Hotttnesss شعبية الأغنية - + Artist Hotttnesss شعبية الفنان - + Artist Familiarity ألفة الفنان - + By Description من خلال الوصف - + Enter a description أدخل الوصف - + Apply steering command طبق أوامر القيادة - + Reset all steering commands إعادة ضبط جميع أوامر القيادة diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 8acbd8195..102168d68 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -2470,92 +2470,92 @@ Try tweaking the filters for a new set of songs to play. Настройки: - + Much less Много по-малко - + Less По-малко - + A bit less Малко по-малко - + Keep at current Запази - + A bit more Малко повече - + More Повече - + Much more Много повече - + Tempo Темпо - + Loudness Сила - + Danceability Танцувалност - + Energy Енергия - + Song Hotttnesss Популярност на изпълненията - + Artist Hotttnesss Популярност на изпълнителя - + Artist Familiarity Близост на изпълнителите - + By Description По описание - + Enter a description Въведи описание - + Apply steering command Приложи избраната команда - + Reset all steering commands Нулирай всички предишни настройки diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index f026b0666..8f867eadc 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -2462,92 +2462,92 @@ Intenteu ajustar els filtres per reproduir noves cançons. Dirigeix aquesta emissora: - + Much less Molt més - + Less Menys - + A bit less Una mica menys - + Keep at current Mantingues a l'actual - + A bit more Una mica més - + More Més - + Much more Molt més - + Tempo Temps - + Loudness Volum - + Danceability Ballabilitat - + Energy Energia - + Song Hotttnesss Rellevància de Cançó - + Artist Hotttnesss Rellevància d'Artista - + Artist Familiarity Semblança amb l'artista - + By Description Per Descripció - + Enter a description Introduïu una descripció - + Apply steering command Aplica la comanda de control - + Reset all steering commands Restaura totes les comandes de control diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 39c221710..413bd8a23 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -2457,92 +2457,92 @@ Versuch die Filter anzupassen für neue Lieder. Steuere diese Station: - + Much less Viel weniger - + Less Weniger - + A bit less Etwas weniger - + Keep at current So belassen - + A bit more Etwas mehr - + More Mehr - + Much more Viel mehr - + Tempo Tempo - + Loudness Lautstärke - + Danceability Tanzbarkeit - + Energy Energie - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity Ähnlichkeit Künstler - + By Description Von der Beschreibung - + Enter a description Gib eine Beschreibung ein - + Apply steering command Steuerkommando anwenden - + Reset all steering commands Setze alle Steuerkommandos zurück diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index eea2c3d51..4169ee32b 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -2463,92 +2463,92 @@ Try tweaking the filters for a new set of songs to play. Steer this station: - + Much less Much less - + Less Less - + A bit less A bit less - + Keep at current Keep at current - + A bit more A bit more - + More More - + Much more Much more - + Tempo Tempo - + Loudness Loudness - + Danceability Danceability - + Energy Energy - + Song Hotttnesss Song Hotttnesss - + Artist Hotttnesss Artist Hotttnesss - + Artist Familiarity Artist Familiarity - + By Description By Description - + Enter a description Enter a description - + Apply steering command Apply steering command - + Reset all steering commands Reset all steering commands diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 6b4f6755d..d5a9fcc8c 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -2461,92 +2461,92 @@ Intente ajustar los filtros para reproducir nuevas canciones. Dirigir esta estación: - + Much less Mucho menos - + Less Menos - + A bit less Un poco menos - + Keep at current Mantener en el actual - + A bit more Un poco más - + More Más - + Much more Mucho más - + Tempo Tempo - + Loudness Volumen - + Danceability Bailabilidad - + Energy Energía - + Song Hotttnesss Popularidad de la pista - + Artist Hotttnesss Popularidad del artista - + Artist Familiarity Familiaridad del artista - + By Description Por descripción - + Enter a description Introducir una descripción - + Apply steering command Aplicar comando - + Reset all steering commands Resetear todos los comandos diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 8a69e7dbe..b4332197b 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -2463,92 +2463,92 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer.Direction de cette station : - + Much less Beaucoup moins - + Less Moins - + A bit less Un peu moins - + Keep at current Garder le même - + A bit more Un peu plus - + More Plus - + Much more Beaucoup plus - + Tempo Tempo - + Loudness Intensité - + Danceability Dansabilité - + Energy Energie - + Song Hotttnesss Hotttnesss du morceau - + Artist Hotttnesss Hotttnesss de l'artiste - + Artist Familiarity Familiarité de l'artiste - + By Description Par description - + Enter a description Entrer une description - + Apply steering command Appliquer la commande de direction - + Reset all steering commands Annuler les commandes de direction diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index c29b529f4..6beddd6eb 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -2459,92 +2459,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 81e6587cf..616362472 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -2457,92 +2457,92 @@ Try tweaking the filters for a new set of songs to play. Steruj tą stacją: - + Much less Dużo mniej - + Less Mniej - + A bit less Trochę mniej - + Keep at current Pozostaw jak jest - + A bit more Trochę więcej - + More Więcej - + Much more Dużo więcej - + Tempo Tempo - + Loudness Głośność - + Danceability Taneczność - + Energy Energiczność - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity Znajomość Artysty - + By Description Po Opisie - + Enter a description Wprowadź opis - + Apply steering command Zastosuj komendę sterowania - + Reset all steering commands Zresetuj wszystkie komendy sterowania diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 722e9ab29..eac92353c 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -2456,92 +2456,92 @@ Try tweaking the filters for a new set of songs to play. Conduzir essa estação: - + Much less Muito menos - + Less Menos - + A bit less Um pouco menos - + Keep at current Manter atual - + A bit more Um pouco mais - + More Mais - + Much more Muito mais - + Tempo Tempo - + Loudness Mais alto - + Danceability Habilidade de dança - + Energy Energia - + Song Hotttnesss Canções preferidas - + Artist Hotttnesss Artistas preferidos - + Artist Familiarity Familiaridade do artista - + By Description Por descrição - + Enter a description Coloque uma descrição - + Apply steering command Aplicar comando de condução - + Reset all steering commands Redefinir todos os comandos de direção diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 53ffac671..f0eb7757e 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -2458,92 +2458,92 @@ Try tweaking the filters for a new set of songs to play. Управляй этой станции: - + Much less Гораздо меньше - + Less Менее - + A bit less Чуть меньше - + Keep at current Имейтся в текущих - + A bit more Немного более - + More Более - + Much more Гораздо больше - + Tempo Ритм - + Loudness - + Danceability - + Energy Мощность - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description По описанию - + Enter a description Введите описание - + Apply steering command - + Reset all steering commands diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 6d464853f..16c156235 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -2452,92 +2452,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less Mycket mindre - + Less Mindre - + A bit less Lite mindre - + Keep at current - + A bit more Lite mer - + More Mer - + Much more Mycket mer - + Tempo Tempo - + Loudness Loudness - + Danceability - + Energy Energi - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description Efter beskrivning - + Enter a description Ange en beskrivning - + Apply steering command - + Reset all steering commands diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 82e608f6b..2fa0b7aaa 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -2451,92 +2451,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 75cb038bb..5661943c8 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -2451,92 +2451,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description - + Apply steering command - + Reset all steering commands diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 96db3de83..03d1a6fd7 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -2451,92 +2451,92 @@ Try tweaking the filters for a new set of songs to play. - + Much less - + Less - + A bit less - + Keep at current - + A bit more - + More - + Much more - + Tempo - + Loudness - + Danceability - + Energy - + Song Hotttnesss - + Artist Hotttnesss - + Artist Familiarity - + By Description - + Enter a description 輸入一個描述 - + Apply steering command - + Reset all steering commands From 28e15122ea0b4e96230a16d5be918f5066870760 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 5 Jun 2012 23:30:57 +0100 Subject: [PATCH 278/433] Live longer, dict --- src/libtomahawk/mac/FileHelpers.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/mac/FileHelpers.mm b/src/libtomahawk/mac/FileHelpers.mm index 97ee3c4ed..6757d4786 100644 --- a/src/libtomahawk/mac/FileHelpers.mm +++ b/src/libtomahawk/mac/FileHelpers.mm @@ -201,7 +201,9 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza if (!success) { NSLog( @"Failed to do non-authenticated move! Help! %@", [[error userInfo] objectForKey: NSLocalizedDescriptionKey] ); } - [self notifyDelegate:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]]; + + NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]; + [self notifyDelegate:dict]; } From 2dc73d04afb901b0e03fd695a78d7edc107354e1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:02:49 +0200 Subject: [PATCH 279/433] * Reuse precalculated connection name. --- src/libtomahawk/database/DatabaseImpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 6ad747104..635796e55 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -742,7 +742,7 @@ DatabaseImpl::openDatabase( const QString& dbname, bool checkSchema ) if ( version > 0 && version != CURRENT_SCHEMA_VERSION ) { - QSqlDatabase::removeDatabase( "tomahawk" ); + QSqlDatabase::removeDatabase( connName ); QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version ); tLog() << endl << "****************************" << endl; @@ -753,7 +753,7 @@ DatabaseImpl::openDatabase( const QString& dbname, bool checkSchema ) QFile::copy( dbname, newname ); { - m_db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" ); + m_db = QSqlDatabase::addDatabase( "QSQLITE", connName ); m_db.setDatabaseName( dbname ); if ( !m_db.open() ) throw "db moving failed"; From 872d8a3da59e8ca6be2021bda10487dc0b665813 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:24:39 +0200 Subject: [PATCH 280/433] * Added TomahawkUtils::msleep( uint ). Sigh. --- src/libtomahawk/utils/TomahawkUtils.cpp | 12 ++++++++++++ src/libtomahawk/utils/TomahawkUtils.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index ddb19dd78..67529673e 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -316,6 +316,18 @@ extensionToMimetype( const QString& extension ) return s_ext2mime.value( extension, "unknown" ); } + +void +msleep( unsigned int ms ) +{ + #ifdef WIN32 + Sleep( ms ); + #else + ::usleep( ms * 1000 ); + #endif +} + + static QMutex s_noProxyHostsMutex; static QStringList s_noProxyHosts; diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index c3b256ca2..e1b0c3e98 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -99,6 +99,8 @@ namespace TomahawkUtils DLLEXPORT QString ageToString( const QDateTime& time, bool appendAgoString = false ); DLLEXPORT QString filesizeToString( unsigned int size ); DLLEXPORT QString extensionToMimetype( const QString& extension ); + + DLLEXPORT void msleep( unsigned int ms ); DLLEXPORT bool newerVersion( const QString& oldVersion, const QString& newVersion ); DLLEXPORT NetworkProxyFactory* proxyFactory( bool makeClone = false, bool noMutexLocker = false ); From d8c3006cb4ca516dc98bd4006c2a848f77e1e7ee Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:25:44 +0200 Subject: [PATCH 281/433] * Added retry blocks for failed (busy) sql queries & commits. --- src/libtomahawk/database/TomahawkSqlQuery.cpp | 27 ++++++++++++++++++- src/libtomahawk/database/TomahawkSqlQuery.h | 4 +++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp index 5a5ea628a..3fbc28f2d 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.cpp +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -18,10 +18,12 @@ #include "database/TomahawkSqlQuery.h" +#include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include #include +#include #include #define QUERY_THRESHOLD 60 @@ -35,6 +37,7 @@ TomahawkSqlQuery::TomahawkSqlQuery() TomahawkSqlQuery::TomahawkSqlQuery( const QSqlDatabase& db ) : QSqlQuery( db ) + , m_db( db ) { } @@ -53,12 +56,20 @@ TomahawkSqlQuery::exec() QTime t; t.start(); - bool ret = QSqlQuery::exec(); + unsigned int retries = 0; + while ( !QSqlQuery::exec() && ++retries < 10 ) + { + tDebug() << "INFO: Retrying failed query:" << this->lastQuery() << this->lastError().text(); + TomahawkUtils::msleep( 25 ); + } + + bool ret = ( retries < 10 ); if ( !ret ) showError(); int e = t.elapsed(); bool log = ( e >= QUERY_THRESHOLD ); + #ifdef TOMAHAWK_QUERY_ANALYZE log = true; #endif @@ -70,6 +81,20 @@ TomahawkSqlQuery::exec() } +bool +TomahawkSqlQuery::commitTransaction() +{ + unsigned int retries = 0; + while ( !m_db.commit() && ++retries < 10 ) + { + tDebug() << "INFO: Retrying failed commit:" << this->lastQuery() << this->lastError().text(); + TomahawkUtils::msleep( 25 ); + } + + return ( retries < 10 ); +} + + void TomahawkSqlQuery::showError() { diff --git a/src/libtomahawk/database/TomahawkSqlQuery.h b/src/libtomahawk/database/TomahawkSqlQuery.h index 8bf1a1495..adb7153d5 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.h +++ b/src/libtomahawk/database/TomahawkSqlQuery.h @@ -34,9 +34,13 @@ public: bool exec( const QString& query ); bool exec(); + + bool commitTransaction(); private: void showError(); + + QSqlDatabase m_db; }; #endif // TOMAHAWKSQLQUERY_H From d481ffbd90aa5d24968dcdefbb774b535df892f1 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:26:12 +0200 Subject: [PATCH 282/433] * Use our own (fail-safer) commit transaction method. --- src/libtomahawk/database/DatabaseWorker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/DatabaseWorker.cpp b/src/libtomahawk/database/DatabaseWorker.cpp index 30481bde3..186012437 100644 --- a/src/libtomahawk/database/DatabaseWorker.cpp +++ b/src/libtomahawk/database/DatabaseWorker.cpp @@ -193,7 +193,7 @@ DatabaseWorker::doWork() if ( cmd->doesMutates() ) { qDebug() << "Committing" << cmd->commandname() << cmd->guid(); - if ( !m_dbimpl->database().commit() ) + if ( !m_dbimpl->newquery().commitTransaction() ) { tDebug() << "FAILED TO COMMIT TRANSACTION*"; throw "commit failed"; From 06d79cd788369e6ff4a0c2182d648f378f209109 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:32:43 +0200 Subject: [PATCH 283/433] * Enable shared qsqlite caches. --- src/libtomahawk/database/DatabaseImpl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 635796e55..123b618e8 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -717,6 +717,7 @@ DatabaseImpl::openDatabase( const QString& dbname, bool checkSchema ) { QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", connName ); db.setDatabaseName( dbname ); + db.setConnectOptions( "QSQLITE_ENABLE_SHARED_CACHE=1" ); if ( !db.open() ) { tLog() << "Failed to open database" << dbname; From 43d2bb77160e884fb346a52c872200938506e480 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:40:06 +0200 Subject: [PATCH 284/433] * Fancy avatars are now scaled ignoring the aspect ratio. This fixed some odd clipping issues. --- src/libtomahawk/utils/TomahawkUtilsGui.cpp | 45 +++++++++++++++------- src/libtomahawk/utils/TomahawkUtilsGui.h | 3 ++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index d0067379f..ccf8cdf2c 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -62,23 +62,24 @@ createDragPixmap( MediaType type, int itemCount ) { xCount = 5; size = 16; - } else if( itemCount > 9 ) + } + else if( itemCount > 9 ) { xCount = 4; size = 22; } - if( itemCount < xCount ) + if ( itemCount < xCount ) { xCount = itemCount; } int yCount = itemCount / xCount; - if( itemCount % xCount != 0 ) + if ( itemCount % xCount != 0 ) { ++yCount; } - if( yCount > xCount ) + if ( yCount > xCount ) { yCount = xCount; } @@ -105,7 +106,7 @@ createDragPixmap( MediaType type, int itemCount ) int x = 0; int y = 0; - for( int i = 0; i < itemCount; ++i ) + for ( int i = 0; i < itemCount; ++i ) { painter.drawPixmap( x, y, pixmap ); @@ -126,9 +127,29 @@ createDragPixmap( MediaType type, int itemCount ) } +void +drawShadowText( QPainter* painter, const QRect& rect, const QString& text, const QTextOption& textOption ) +{ + painter->save(); + + painter->drawText( rect, text, textOption ); + +/* QFont font = painter->font(); + font.setPixelSize( font.pixelSize() + 2 ); + painter->setFont( font ); + + painter->setPen( Qt::black ); + painter->drawText( rect, text, textOption );*/ + + painter->restore(); +} + + void drawBackgroundAndNumbers( QPainter* painter, const QString& text, const QRect& figRectIn ) { + painter->save(); + QRect figRect = figRectIn; if ( text.length() == 1 ) figRect.adjust( -painter->fontMetrics().averageCharWidth(), 0, 0, 0 ); @@ -155,15 +176,13 @@ drawBackgroundAndNumbers( QPainter* painter, const QString& text, const QRect& f ppath.arcTo( leftArcRect, 270, 180 ); painter->drawPath( ppath ); - painter->setPen( origpen ); - -#ifdef Q_WS_MAC figRect.adjust( -1, 0, 0, 0 ); -#endif - QTextOption to( Qt::AlignCenter ); + painter->setPen( origpen ); painter->setPen( Qt::white ); - painter->drawText( figRect.adjusted( -5, 0, 6, 0 ), text, to ); + painter->drawText( figRect.adjusted( -5, 0, 6, 0 ), text, QTextOption( Qt::AlignCenter ) ); + + painter->restore(); } @@ -277,10 +296,10 @@ QPixmap createAvatarFrame( const QPixmap &avatar ) { QPixmap frame( ":/data/images/avatar_frame.png" ); - QPixmap scaledAvatar = avatar.scaled( frame.height() * 75 / 100, frame.width() * 75 / 100, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + QPixmap scaledAvatar = avatar.scaled( frame.height() * 75 / 100, frame.width() * 75 / 100, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); QPainter painter( &frame ); - painter.drawPixmap( (frame.height() - scaledAvatar.height()) / 2, (frame.width() - scaledAvatar.width()) / 2, scaledAvatar ); + painter.drawPixmap( ( frame.height() - scaledAvatar.height() ) / 2, ( frame.width() - scaledAvatar.width() ) / 2, scaledAvatar ); return frame; } diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.h b/src/libtomahawk/utils/TomahawkUtilsGui.h index 79cf6e5a2..1c89f8bce 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.h +++ b/src/libtomahawk/utils/TomahawkUtilsGui.h @@ -22,6 +22,7 @@ #include #include +#include #include "TomahawkUtils.h" #include "DllMacro.h" @@ -47,7 +48,9 @@ namespace TomahawkUtils DLLEXPORT QColor alphaBlend( const QColor& colorFrom, const QColor& colorTo, float opacity ); DLLEXPORT QPixmap createDragPixmap( MediaType type, int itemCount = 1 ); + DLLEXPORT void drawShadowText( QPainter* p, const QRect& rect, const QString& text, const QTextOption& textOption ); DLLEXPORT void drawBackgroundAndNumbers( QPainter* p, const QString& text, const QRect& rect ); + DLLEXPORT void unmarginLayout( QLayout* layout ); DLLEXPORT int headerHeight(); From 447536958e77c50102212001635294549ef5fdee Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:42:22 +0200 Subject: [PATCH 285/433] * Give sidebar figures a bit more space and use a thicker font. --- src/sourcetree/SourceDelegate.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sourcetree/SourceDelegate.cpp b/src/sourcetree/SourceDelegate.cpp index bd3c4a8eb..4f2f35670 100644 --- a/src/sourcetree/SourceDelegate.cpp +++ b/src/sourcetree/SourceDelegate.cpp @@ -145,10 +145,13 @@ SourceDelegate::paintDecorations( QPainter* painter, const QStyleOptionViewItem& void SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { - QFont normal = painter->font(); - QFont bold = painter->font(); + QFont normal = option.font; + QFont bold = option.font; bold.setBold( true ); + QFont figFont = bold; + figFont.setFamily( "Arial Bold" ); + figFont.setWeight( QFont::Black ); figFont.setPixelSize( 10 ); SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >(); @@ -254,7 +257,7 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& { painter->setRenderHint( QPainter::Antialiasing ); - QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 8, 0, -13, -option.rect.height() + 16 ); + QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 13, 0, -14, -option.rect.height() + 16 ); int hd = ( option.rect.height() - figRect.height() ) / 2; figRect.adjust( 0, hd, 0, hd ); From 6d48ffc298c7b57351b3c3662960314e63832b20 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:45:03 +0200 Subject: [PATCH 286/433] * One pixel more space for WelcomeWidget's figures. --- src/libtomahawk/widgets/WelcomeWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/WelcomeWidget.cpp b/src/libtomahawk/widgets/WelcomeWidget.cpp index e7162802a..a2c16943c 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.cpp +++ b/src/libtomahawk/widgets/WelcomeWidget.cpp @@ -241,7 +241,7 @@ PlaylistDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, // right edge 10px past right edge of pixmapRect // bottom edge flush with bottom of pixmap QRect rect( pixmapRect.right() - width , 0, width - 8, 0 ); - rect.adjust( -1, 0, 0, 0 ); + rect.adjust( -2, 0, 0, 0 ); rect.setTop( pixmapRect.bottom() - painter->fontMetrics().height() - 1 ); rect.setBottom( pixmapRect.bottom() + 1 ); From 8c9deaf4ac8694db5b517f8533b4ce3792c39cd4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 6 Jun 2012 16:45:33 +0200 Subject: [PATCH 287/433] * More accurate debug output. --- src/libtomahawk/database/DatabaseImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 123b618e8..1119f58a8 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -113,7 +113,7 @@ DatabaseImpl::init() DatabaseImpl::~DatabaseImpl() { - tDebug() << "Shutting down database."; + tDebug() << "Shutting down database connection."; /* #ifdef TOMAHAWK_QUERY_ANALYZE From 0fd008ba412a6431cb76b8cb73aeba222e312f4e Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Wed, 6 Jun 2012 14:55:41 -0400 Subject: [PATCH 288/433] Changelogify. What did I miss? --- ChangeLog | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 81835c77b..0fa6c3c4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,13 +1,32 @@ Version 0.5.0: - * Support .aiff (AIFF mimetype) files. - * Added "Stop playback after this track" context menu items. - * You can now import your entire Last.fm playback history into Tomahawk. - * Support for multimedia keys (Play, Pause, Next etc.) on Windows & Linux. - * When listening privately scrobbling to Last.fm is now disabled. - * Added a toolbar with page back / forward buttons and the global search. - * New grid view with direct playback controls. - * Added a track page showing a song's lyrics and other similar tracks. + * Priortize resolution of a track on double-click + * New Tomahawk logo and icon + * Spotify Resolver shipped with Tomahawk and installable via new Preferences interface + * Sync select playlists (and updates) with Spotify + * Support .aiff (AIFF mimetype) files + * Cleaned up Diagnostics window + * Don't show non-resolved tracks as Recently Played + * Added "Stop playback after this track" context menu items + * Double-clicking on a playlist name (in the sidebar) will play the playlist + * You can now import your entire Last.fm playback history into Tomahawk + * Related Artists now sorted by relatedness + * Support for multimedia keys (Play, Pause, Next etc.) on Windows & Linux + * When listening privately scrobbling to Last.fm and Adium is now disabled + * Added a toolbar with page back / forward buttons and the global search + * New grid view with direct playback controls (Charts, Album Page, Artist Page, Track Page) + * New Releases (by Genre) pages added + * Add social sharing widget in Now Playing Controls + * Added a track page showing a song's lyrics and other similar tracks + * Selecting Track name in Now Playing now brings you to Track page * Separate Loved Tracks and Recently Played views per source. + * Added animated spinner where needed + * Some new sidebar icons + * Support Transifex for localization and add translations for Arabic, French, Bulgarian, Catalan, Spanish (Castillian), and more. + * New Context Menu items (Love, Add to Queue, etc.) + * Fading album art + * New Account and Plug-in Preferences/Management Interface + * Fix XSPF auto-updating + Version 0.4.2: * Fix ZeroConf protocol showing IP addresses instead of host names. From 94a8aaced7e8d373e5e195768d4f71305e87ffae Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Wed, 6 Jun 2012 22:17:01 +0000 Subject: [PATCH 289/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 14 +++++++------- lang/tomahawk_bg.ts | 14 +++++++------- lang/tomahawk_ca.ts | 14 +++++++------- lang/tomahawk_de.ts | 14 +++++++------- lang/tomahawk_en.ts | 14 +++++++------- lang/tomahawk_es.ts | 14 +++++++------- lang/tomahawk_fr.ts | 36 ++++++++++++++++++------------------ lang/tomahawk_ja.ts | 14 +++++++------- lang/tomahawk_pl.ts | 14 +++++++------- lang/tomahawk_pt_BR.ts | 14 +++++++------- lang/tomahawk_ru.ts | 14 +++++++------- lang/tomahawk_sv.ts | 14 +++++++------- lang/tomahawk_tr.ts | 14 +++++++------- lang/tomahawk_zh_CN.ts | 14 +++++++------- lang/tomahawk_zh_TW.ts | 14 +++++++------- 15 files changed, 116 insertions(+), 116 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 30940d14f..f90629ba0 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -1131,29 +1131,29 @@ connect and stream from you? توب ١٠ - + Offline غير متصل - + All available tracks جميع الأغاني المتاحة - + Online متصل - - + + Show أظهر - - + + Hide إخفي diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 102168d68..41f559284 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -1131,29 +1131,29 @@ Tomahaw създаде доклад относно това и изпращай Първите 10 - + Offline Извън линия - + All available tracks Всички налични изпълнения - + Online На линия - - + + Show Покажи - - + + Hide Скрий diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 8f867eadc..36fcee927 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -1129,29 +1129,29 @@ connect and stream from you? Top 10 - + Offline Fora de Línia - + All available tracks Totes les cançons disponibles - + Online En Línia - - + + Show Mostra - - + + Hide Amaga diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 413bd8a23..d3e798d89 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -1129,29 +1129,29 @@ connect and stream from you? Top 10 - + Offline Nicht Verbunden - + All available tracks Alle verfügbaren Stücke - + Online Verbunden - - + + Show Einblenden - - + + Hide Verstecken diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 4169ee32b..ffd1c8263 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -1130,29 +1130,29 @@ connect and stream from you? Top 10 - + Offline Offline - + All available tracks All available tracks - + Online Online - - + + Show Show - - + + Hide Hide diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index d5a9fcc8c..425c4a4d4 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -1128,29 +1128,29 @@ connect and stream from you? Top 10 - + Offline Desconectado - + All available tracks Todas las pistas disponibles - + Online Conectado - - + + Show Mostrar - - + + Hide Ocultar diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index b4332197b..6418697a7 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -745,7 +745,7 @@ se connecter et streamer depuis chez vous ? Don't know exactly what you want? Give Tomahawk a few pointers and let it build a playlist for you! - Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous! + Vous ne savez pas ce que vous voulez exactement ? Donnez quelques idées à Tomahawk et laissez le créer une liste de lecture pour vous ! @@ -760,12 +760,12 @@ se connecter et streamer depuis chez vous ? Create Manual Playlist - Créer une liste de lecture manuellement + Liste de lecture manuelle Create Automatic Playlist - Créer une liste de lecture automatiquement + Liste de lecture automatique @@ -1130,29 +1130,29 @@ se connecter et streamer depuis chez vous ? Top 10 - + Offline Hors ligne - + All available tracks Tous les titres disponibles - + Online En Ligne - - + + Show Afficher - - + + Hide Masquer @@ -1284,7 +1284,7 @@ se connecter et streamer depuis chez vous ? Add to my Stations - Ajoute a mes stations + Ajouter à mes stations @@ -1497,9 +1497,9 @@ se connecter et streamer depuis chez vous ? will allow you (and all your friends) to create automatic playlists and stations based on your personal taste profile. The Echo Nest peut garder les métadonnées de votre catalogue -et l'utiliser pour créer des radios personnalisées. En activant cette option +et les utiliser pour créer des radios personnalisées. En activant cette option vous (et vos amis) pourrez créer des listes de lecture automatiquement -et des stations basés sur vos goûts. +et des stations basées sur vos goûts. @@ -1941,7 +1941,7 @@ Essayez de vous authentifier de nouveau. Log on to your Jabber/XMPP account to connect to your friends - Connectez vous à votre compte Jabber/XMPP pour vous connecter avec vos amis + Connectez vous à votre compte Jabber/XMPP pour retrouver vos amis @@ -2460,7 +2460,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Steer this station: - Direction de cette station : + Modifier cette station : @@ -2646,7 +2646,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Error fetching iTunes information from the network! - Échec du chargement des informations iTunes depuis le réseau! + Échec du chargement des informations iTunes depuis le réseau ! @@ -2726,7 +2726,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. loved this track - a mis cette piste en favoris + a enregistré cette piste dans ses favoris @@ -3528,7 +3528,7 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env Newest Stations & Playlists - Dernières stations & listes de lecture + Dernières stations et listes de lecture diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 6beddd6eb..146e38faf 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -1136,29 +1136,29 @@ other: %n週間 - + Offline オフライン - + All available tracks - + Online オンライン - - + + Show - - + + Hide diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 616362472..07fd1a62a 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -1128,29 +1128,29 @@ connect and stream from you? Top 10 - + Offline Offline - + All available tracks Wszystkie dostępne utwory - + Online Online - - + + Show Pokaż - - + + Hide Ukryj diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index eac92353c..08638cdd5 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -1128,29 +1128,29 @@ connect and stream from you? 10 Mais - + Offline Desconectado - + All available tracks Todas as faixas disponíveis - + Online Conectado - - + + Show Mostrar - - + + Hide Ocultar diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index f0eb7757e..2dfec0f95 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -1130,29 +1130,29 @@ connect and stream from you? Топ 10 - + Offline Не в сети - + All available tracks Доступные песни - + Online В сети - - + + Show Показать - - + + Hide Спрятать diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 16c156235..7792db58b 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1129,29 +1129,29 @@ connect and stream from you? Topp 10 - + Offline Frånkopplad - + All available tracks Alla tillgängliga spår - + Online Ansluten - - + + Show Visa - - + + Hide Göm diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 2fa0b7aaa..bf2ef0982 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -1128,29 +1128,29 @@ connect and stream from you? - + Offline - + All available tracks - + Online - - + + Show - - + + Hide diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 5661943c8..f1a31bb71 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -1128,29 +1128,29 @@ connect and stream from you? - + Offline - + All available tracks - + Online - - + + Show - - + + Hide diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 03d1a6fd7..e15854c15 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -1128,29 +1128,29 @@ connect and stream from you? 前10名 - + Offline 離線 - + All available tracks - + Online 線上 - - + + Show 顯示 - - + + Hide 隱藏 From e550ffe2b04f926f42ae79ce4afc3266b2de366f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:07:51 +0200 Subject: [PATCH 290/433] * Immediately clear the a source's current track pointer after playback finished. --- src/libtomahawk/Source.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index 53f46bf32..88fefcd4c 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -362,7 +362,7 @@ Source::playlistInterface() void Source::onPlaybackStarted( const Tomahawk::query_ptr& query, unsigned int duration ) { - qDebug() << Q_FUNC_INFO << query->toString(); + tLog( LOGVERBOSE ) << Q_FUNC_INFO << query->toString(); m_currentTrack = query; m_currentTrackTimer.start( duration * 1000 + 900000 ); // duration comes in seconds @@ -376,10 +376,10 @@ Source::onPlaybackStarted( const Tomahawk::query_ptr& query, unsigned int durati void Source::onPlaybackFinished( const Tomahawk::query_ptr& query ) { - qDebug() << Q_FUNC_INFO << query->toString(); + tDebug() << Q_FUNC_INFO << query->toString(); emit playbackFinished( query ); - m_currentTrackTimer.start(); + m_currentTrack.clear(); } From f57c0c5b748e685414466c939790e16ded80ebca Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:11:12 +0200 Subject: [PATCH 291/433] * More consistent stateChanged() behaviour for sources. --- src/libtomahawk/Source.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index 88fefcd4c..9f98d4b02 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -369,7 +369,9 @@ Source::onPlaybackStarted( const Tomahawk::query_ptr& query, unsigned int durati if ( m_playlistInterface.isNull() ) playlistInterface(); + emit playbackStarted( query ); + emit stateChanged(); } @@ -380,6 +382,7 @@ Source::onPlaybackFinished( const Tomahawk::query_ptr& query ) emit playbackFinished( query ); m_currentTrack.clear(); + emit stateChanged(); } @@ -387,7 +390,6 @@ void Source::trackTimerFired() { m_currentTrack.clear(); - emit stateChanged(); } From 1df157976a12234eaeb554aa7b4ef7ba6bf16083 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:11:43 +0200 Subject: [PATCH 292/433] * We can rely on stateChanged() signal for updating a source's sidebar info now. --- src/sourcetree/items/SourceItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sourcetree/items/SourceItem.cpp b/src/sourcetree/items/SourceItem.cpp index b495f4f23..03f7be0db 100644 --- a/src/sourcetree/items/SourceItem.cpp +++ b/src/sourcetree/items/SourceItem.cpp @@ -113,7 +113,6 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw connect( source.data(), SIGNAL( stats( QVariantMap ) ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( syncedWithDatabase() ), SIGNAL( updated() ) ); - connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( stateChanged() ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( offline() ), SIGNAL( updated() ) ); connect( source.data(), SIGNAL( online() ), SIGNAL( updated() ) ); From 25ef791afc0c060901b52a43b42866d2b61f2ce2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:12:01 +0200 Subject: [PATCH 293/433] * Style fix, once again. --- src/libtomahawk/TomahawkSettingsGui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/TomahawkSettingsGui.cpp b/src/libtomahawk/TomahawkSettingsGui.cpp index 8aa15b3c2..2e6932fda 100644 --- a/src/libtomahawk/TomahawkSettingsGui.cpp +++ b/src/libtomahawk/TomahawkSettingsGui.cpp @@ -61,6 +61,7 @@ inline QDataStream& operator>>(QDataStream& in, AtticaManager::StateHash& states return in; } + TomahawkSettingsGui* TomahawkSettingsGui::instanceGui() { @@ -109,12 +110,14 @@ TomahawkSettingsGui::setAtticaResolverState( const QString& resolver, AtticaMana sync(); } + AtticaManager::StateHash TomahawkSettingsGui::atticaResolverStates() const { return value( "script/atticaresolverstates" ).value< AtticaManager::StateHash >(); } + void TomahawkSettingsGui::setAtticaResolverStates( const AtticaManager::StateHash states ) { From 9443992ff9b7d42de7c58582e604eb2f368670df Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:20:55 +0200 Subject: [PATCH 294/433] * Keep retrying sql queries forever, as long as the returned db error indicates the db is just busy / locked. --- src/libtomahawk/database/TomahawkSqlQuery.cpp | 31 ++++++++++++++----- src/libtomahawk/database/TomahawkSqlQuery.h | 2 ++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp index 3fbc28f2d..d62c02351 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.cpp +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -59,8 +59,11 @@ TomahawkSqlQuery::exec() unsigned int retries = 0; while ( !QSqlQuery::exec() && ++retries < 10 ) { - tDebug() << "INFO: Retrying failed query:" << this->lastQuery() << this->lastError().text(); - TomahawkUtils::msleep( 25 ); + if ( isBusyError( lastError() ) ) + retries = 0; + + tDebug() << "INFO: Retrying failed query:" << lastQuery() << lastError().text(); + TomahawkUtils::msleep( 10 ); } bool ret = ( retries < 10 ); @@ -87,8 +90,11 @@ TomahawkSqlQuery::commitTransaction() unsigned int retries = 0; while ( !m_db.commit() && ++retries < 10 ) { - tDebug() << "INFO: Retrying failed commit:" << this->lastQuery() << this->lastError().text(); - TomahawkUtils::msleep( 25 ); + if ( isBusyError( lastError() ) ) + retries = 0; + + tDebug() << "INFO: Retrying failed commit:" << lastQuery() << lastError().text(); + TomahawkUtils::msleep( 10 ); } return ( retries < 10 ); @@ -98,10 +104,19 @@ TomahawkSqlQuery::commitTransaction() void TomahawkSqlQuery::showError() { - tLog() << "\n" << "*** DATABASE ERROR ***" << "\n" - << this->lastQuery() << "\n" - << "boundValues:" << this->boundValues() << "\n" - << this->lastError().text() << "\n"; + tLog() << endl << "*** DATABASE ERROR ***" << endl + << lastQuery() << endl + << "boundValues:" << boundValues() << endl + << lastError().text() << endl; Q_ASSERT( false ); } + + +bool +TomahawkSqlQuery::isBusyError( const QSqlError& error ) +{ + const QString text = error.text().toLower(); + + return ( text.contains( "locked" ) || text.contains( "busy" ) ); +} diff --git a/src/libtomahawk/database/TomahawkSqlQuery.h b/src/libtomahawk/database/TomahawkSqlQuery.h index adb7153d5..ad00caa11 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.h +++ b/src/libtomahawk/database/TomahawkSqlQuery.h @@ -38,6 +38,8 @@ public: bool commitTransaction(); private: + bool isBusyError( const QSqlError& error ); + void showError(); QSqlDatabase m_db; From 14ee71e6654746a87b4f8a0107001e974b96d8d5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:33:08 +0200 Subject: [PATCH 295/433] * Added a convenient sql escaping method to TomahawkSqlQuery. It uses the sql drivers internal escaping mechanism. --- src/libtomahawk/database/TomahawkSqlQuery.cpp | 11 ++++++++++- src/libtomahawk/database/TomahawkSqlQuery.h | 5 ++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp index d62c02351..b57274b6e 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.cpp +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -18,6 +18,8 @@ #include "database/TomahawkSqlQuery.h" +#include "database/Database.h" +#include "database/DatabaseImpl.h" #include "utils/TomahawkUtils.h" #include "utils/Logger.h" @@ -42,6 +44,13 @@ TomahawkSqlQuery::TomahawkSqlQuery( const QSqlDatabase& db ) } +QString +TomahawkSqlQuery::escape( const QString& identifier, QSqlDriver::IdentifierType type ) +{ + return Database::instance()->impl()->database().driver()->escapeIdentifier( identifier, type ); +} + + bool TomahawkSqlQuery::exec( const QString& query ) { @@ -114,7 +123,7 @@ TomahawkSqlQuery::showError() bool -TomahawkSqlQuery::isBusyError( const QSqlError& error ) +TomahawkSqlQuery::isBusyError( const QSqlError& error ) const { const QString text = error.text().toLower(); diff --git a/src/libtomahawk/database/TomahawkSqlQuery.h b/src/libtomahawk/database/TomahawkSqlQuery.h index ad00caa11..a54543a35 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.h +++ b/src/libtomahawk/database/TomahawkSqlQuery.h @@ -21,6 +21,7 @@ // subclass QSqlQuery so that it prints the error msg if a query fails +#include #include #define TOMAHAWK_QUERY_ANALYZE 1 @@ -32,13 +33,15 @@ public: TomahawkSqlQuery(); TomahawkSqlQuery( const QSqlDatabase& db ); + static QString escape( const QString& identifier, QSqlDriver::IdentifierType type = QSqlDriver::FieldName ); + bool exec( const QString& query ); bool exec(); bool commitTransaction(); private: - bool isBusyError( const QSqlError& error ); + bool isBusyError( const QSqlError& error ) const; void showError(); From 077409ae7e752fe1a073c85813576ece5f7a7314 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:33:56 +0200 Subject: [PATCH 296/433] * Use TomahawkSqlQuery's new escaping method. --- src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp | 2 +- src/libtomahawk/database/DatabaseCommand_AllArtists.cpp | 2 +- src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp index d72716e01..cfc7c9165 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllAlbums.cpp @@ -73,7 +73,7 @@ DatabaseCommand_AllAlbums::execForArtist( DatabaseImpl* dbi ) QStringList sl = m_filter.split( " ", QString::SkipEmptyParts ); foreach( QString s, sl ) { - filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkUtils::sqlEscape( s ) ); + filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkSqlQuery::escape( s ) ); } filterToken = QString( "AND artist.id = file_join.artist AND file_join.track = track.id %1" ).arg( filtersql ); diff --git a/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp b/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp index c9479a345..5d030d1ac 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllArtists.cpp @@ -63,7 +63,7 @@ DatabaseCommand_AllArtists::exec( DatabaseImpl* dbi ) QStringList sl = m_filter.split( " ", QString::SkipEmptyParts ); foreach( QString s, sl ) { - filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkUtils::sqlEscape( s ) ); + filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkSqlQuery::escape( s ) ); } filterToken = QString( "AND file_join.track = track.id %1" ).arg( filtersql ); diff --git a/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp b/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp index 0fd08a9bd..38e968bbc 100644 --- a/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp +++ b/src/libtomahawk/database/DatabaseCommand_DeleteFiles.cpp @@ -81,7 +81,7 @@ DatabaseCommand_DeleteFiles::exec( DatabaseImpl* dbi ) tDebug() << "Deleting" << m_dir.path() << "from db for localsource" << srcid; TomahawkSqlQuery dirquery = dbi->newquery(); QString path( "file://" + m_dir.canonicalPath() + "/%" ); - dirquery.prepare( QString( "SELECT id FROM file WHERE source IS NULL AND url LIKE '%1'" ).arg( TomahawkUtils::sqlEscape( path ) ) ); + dirquery.prepare( QString( "SELECT id FROM file WHERE source IS NULL AND url LIKE '%1'" ).arg( TomahawkSqlQuery::escape( path ) ) ); dirquery.exec(); while ( dirquery.next() ) From 8c9d209940ee692c6b41a539baf29c5406f43e90 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:34:20 +0200 Subject: [PATCH 297/433] * Removed old sql escaping helper in TomahawkUtils. --- src/libtomahawk/utils/TomahawkUtils.cpp | 7 ------- src/libtomahawk/utils/TomahawkUtils.h | 1 - 2 files changed, 8 deletions(-) diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index 67529673e..83cfbf821 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -178,13 +178,6 @@ appLogDir() } -QString -sqlEscape( QString sql ) -{ - return sql.replace( "'", "''" ); -} - - QString timeToString( int seconds ) { diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index e1b0c3e98..5da2fab30 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -94,7 +94,6 @@ namespace TomahawkUtils DLLEXPORT QDir appDataDir(); DLLEXPORT QDir appLogDir(); - DLLEXPORT QString sqlEscape( QString sql ); DLLEXPORT QString timeToString( int seconds ); DLLEXPORT QString ageToString( const QDateTime& time, bool appendAgoString = false ); DLLEXPORT QString filesizeToString( unsigned int size ); From 8ba433afa5de20f444ea1d3c34db5d37b12a2100 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:55:34 +0200 Subject: [PATCH 298/433] * Ignore incompatible models. --- src/libtomahawk/widgets/OverlayWidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index aa6b846ba..be455af57 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -153,8 +153,10 @@ OverlayWidget::onViewChanged() return; PlayableProxyModel* model = qobject_cast( m_itemView->model() ); + if ( !model ) + return; - if ( m_text.isEmpty() || ( model && ( model->rowCount( QModelIndex() ) || model->isLoading() ) ) ) + if ( m_text.isEmpty() || model->rowCount( QModelIndex() ) || model->isLoading() ) { hide(); } From acc4fa8c9aff4862c2c0b4848c3ce3e2effeb071 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 08:56:08 +0200 Subject: [PATCH 299/433] * Emit loadingStarted() / -Finished() signals from RecentPlaylistsModel. --- src/libtomahawk/widgets/RecentPlaylistsModel.cpp | 3 +++ src/libtomahawk/widgets/RecentPlaylistsModel.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/libtomahawk/widgets/RecentPlaylistsModel.cpp b/src/libtomahawk/widgets/RecentPlaylistsModel.cpp index 573f02e07..ba0eca7bd 100644 --- a/src/libtomahawk/widgets/RecentPlaylistsModel.cpp +++ b/src/libtomahawk/widgets/RecentPlaylistsModel.cpp @@ -63,6 +63,8 @@ RecentPlaylistsModel::onRefresh() if ( m_timer->isActive() ) m_timer->stop(); + emit loadingStarted(); + DatabaseCommand_LoadAllSortedPlaylists* cmd = new DatabaseCommand_LoadAllSortedPlaylists( source_ptr() ); cmd->setLimit( 15 ); cmd->setSortOrder( DatabaseCommand_LoadAllPlaylists::ModificationTime ); @@ -117,6 +119,7 @@ RecentPlaylistsModel::playlistsLoaded( const QList Date: Thu, 7 Jun 2012 08:57:04 +0200 Subject: [PATCH 300/433] * Show a loading spinner for 'Newest Stations / Playlists'. --- src/libtomahawk/widgets/WelcomeWidget.cpp | 11 +++++++++++ src/libtomahawk/widgets/WelcomeWidget.h | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/src/libtomahawk/widgets/WelcomeWidget.cpp b/src/libtomahawk/widgets/WelcomeWidget.cpp index a2c16943c..0280b3285 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.cpp +++ b/src/libtomahawk/widgets/WelcomeWidget.cpp @@ -32,6 +32,7 @@ #include "playlist/AlbumModel.h" #include "playlist/RecentlyPlayedModel.h" #include "widgets/OverlayWidget.h" +#include "utils/AnimatedSpinner.h" #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "dynamic/GeneratorInterface.h" @@ -307,4 +308,14 @@ PlaylistWidget::PlaylistWidget( QWidget* parent ) : QListView( parent ) { m_overlay = new OverlayWidget( this ); + LoadingSpinner* spinner = new LoadingSpinner( this ); } + + +void +PlaylistWidget::setModel( QAbstractItemModel* model ) +{ + QListView::setModel( model ); + emit modelChanged(); +} + diff --git a/src/libtomahawk/widgets/WelcomeWidget.h b/src/libtomahawk/widgets/WelcomeWidget.h index bb5754fce..658f6e8aa 100644 --- a/src/libtomahawk/widgets/WelcomeWidget.h +++ b/src/libtomahawk/widgets/WelcomeWidget.h @@ -64,12 +64,20 @@ private: QPixmap m_playlistIcon, m_autoIcon, m_stationIcon, m_defaultAvatar; }; + class DLLEXPORT PlaylistWidget : public QListView { +Q_OBJECT + public: PlaylistWidget( QWidget* parent = 0 ); OverlayWidget* overlay() const { return m_overlay; } + + virtual void setModel( QAbstractItemModel* model ); + +signals: + void modelChanged(); private: OverlayWidget* m_overlay; From 1b743b0e9d3539c93d84e436b1e0688d21ece54b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 09:16:37 +0200 Subject: [PATCH 301/433] * Let local source know when we go off- / online. --- src/libtomahawk/Source.cpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index 9f98d4b02..26e15dd40 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -23,6 +23,7 @@ #include "SourceList.h" #include "SourcePlaylistInterface.h" +#include "accounts/AccountManager.h" #include "network/ControlConnection.h" #include "database/DatabaseCommand_AddSource.h" #include "database/DatabaseCommand_CollectionStats.h" @@ -65,6 +66,12 @@ Source::Source( int id, const QString& username ) m_currentTrackTimer.setSingleShot( true ); connect( &m_currentTrackTimer, SIGNAL( timeout() ), this, SLOT( trackTimerFired() ) ); + + if ( m_isLocal ) + { + connect( Accounts::AccountManager::instance(), SIGNAL( connected( Tomahawk::Accounts::Account* ) ), SLOT( setOnline() ) ); + connect( Accounts::AccountManager::instance(), SIGNAL( disconnected( Tomahawk::Accounts::Account* ) ), SLOT( setOffline() ) ); + } } @@ -228,12 +235,15 @@ Source::setOffline() m_online = false; emit offline(); - m_currentTrack.clear(); - emit stateChanged(); + if ( !isLocal() ) + { + m_currentTrack.clear(); + emit stateChanged(); - m_cc = 0; - DatabaseCommand_SourceOffline* cmd = new DatabaseCommand_SourceOffline( id() ); - Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); + m_cc = 0; + DatabaseCommand_SourceOffline* cmd = new DatabaseCommand_SourceOffline( id() ); + Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) ); + } } @@ -247,11 +257,14 @@ Source::setOnline() m_online = true; emit online(); - // ensure username is in the database - DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, friendlyName() ); - connect( cmd, SIGNAL( done( unsigned int, QString ) ), - SLOT( dbLoaded( unsigned int, const QString& ) ) ); - Database::instance()->enqueue( QSharedPointer(cmd) ); + if ( !isLocal() ) + { + // ensure username is in the database + DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, friendlyName() ); + connect( cmd, SIGNAL( done( unsigned int, QString ) ), + SLOT( dbLoaded( unsigned int, const QString& ) ) ); + Database::instance()->enqueue( QSharedPointer(cmd) ); + } } From 0d85d15002db23e44694ee8d99d58c2c716c3d5c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 09:35:35 +0200 Subject: [PATCH 302/433] * Manage source's off-/online state for the local source, too. --- src/libtomahawk/Source.cpp | 26 +++++++++++++++++++++++--- src/libtomahawk/Source.h | 4 ++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index 26e15dd40..db331385f 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -59,10 +59,7 @@ Source::Source( int id, const QString& username ) m_scrubFriendlyName = qApp->arguments().contains( "--demo" ); if ( id == 0 ) - { m_isLocal = true; - m_online = true; - } m_currentTrackTimer.setSingleShot( true ); connect( &m_currentTrackTimer, SIGNAL( timeout() ), this, SLOT( trackTimerFired() ) ); @@ -524,3 +521,26 @@ Source::updateIndexWhenSynced() { m_updateIndexWhenSynced = true; } + + +QString +Source::textStatus() const +{ + if ( !m_textStatus.isEmpty() ) + return m_textStatus; + + if ( !currentTrack().isNull() ) + { + return currentTrack()->artist() + " - " + currentTrack()->track(); + } + + // do not use isOnline() here - it will always return true for the local source + if ( m_online ) + { + return tr( "Online" ); + } + else + { + return tr( "Offline" ); + } +} diff --git a/src/libtomahawk/Source.h b/src/libtomahawk/Source.h index 883b605dc..bd463ae2a 100644 --- a/src/libtomahawk/Source.h +++ b/src/libtomahawk/Source.h @@ -58,7 +58,7 @@ public: virtual ~Source(); bool isLocal() const { return m_isLocal; } - bool isOnline() const { return m_online; } + bool isOnline() const { return m_online || m_isLocal; } QString userName() const { return m_username; } QString friendlyName() const; @@ -83,7 +83,7 @@ public: unsigned int trackCount() const; Tomahawk::query_ptr currentTrack() const { return m_currentTrack; } - QString textStatus() const { return m_textStatus; } + QString textStatus() const; DBSyncConnection::State state() const { return m_state; } Tomahawk::playlistinterface_ptr playlistInterface(); From 18a1ed4c7df5a6e8e35a033e6ab33c6424024e4d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 09:37:28 +0200 Subject: [PATCH 303/433] * Less work for SourceDelegate now. --- src/sourcetree/SourceDelegate.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/sourcetree/SourceDelegate.cpp b/src/sourcetree/SourceDelegate.cpp index 4f2f35670..1f434a924 100644 --- a/src/sourcetree/SourceDelegate.cpp +++ b/src/sourcetree/SourceDelegate.cpp @@ -186,17 +186,10 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() ); painter->drawText( textRect, text ); - bool isPlaying = false; - QString desc = status ? colItem->source()->textStatus() : tr( "Offline" ); + bool isPlaying = !( colItem->source()->currentTrack().isNull() ); + QString desc = colItem->source()->textStatus(); if ( colItem->source().isNull() ) desc = tr( "All available tracks" ); - if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() ) - { - desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track(); - isPlaying = true; - } - if ( desc.isEmpty() ) - desc = tr( "Online" ); painter->setFont( normal ); textRect = option.rect.adjusted( iconRect.width() + 8, option.rect.height() / 2, -figWidth - 24, -6 ); From 96e12a0f90f921ca19e7231fd22e2ba016c7a390 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 10:37:31 +0200 Subject: [PATCH 304/433] * Register Tomahawk::Resolver* as a meta-type. --- src/TomahawkApp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 0b46c7f1e..baf919ee1 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -445,6 +445,7 @@ TomahawkApp::registerMetaTypes() qRegisterMetaType("Tomahawk::ModelMode"); // Extra definition for namespaced-versions of signals/slots required + qRegisterMetaType< Tomahawk::Resolver* >("Tomahawk::Resolver*"); qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr"); qRegisterMetaType< Tomahawk::collection_ptr >("Tomahawk::collection_ptr"); qRegisterMetaType< Tomahawk::result_ptr >("Tomahawk::result_ptr"); From ff50bcb54565190d60e5f2ae44bc3976c222635a Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 10:37:58 +0200 Subject: [PATCH 305/433] * Fixed slot signature. --- src/libtomahawk/Pipeline.cpp | 1 + src/libtomahawk/Pipeline.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index 8fb42a00b..6e12e5734 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -106,6 +106,7 @@ Pipeline::removeResolver( Resolver* r ) { QMutexLocker lock( &m_mut ); + tDebug() << "Removed resolver:" << r->name(); m_resolvers.removeAll( r ); emit resolverRemoved( r ); } diff --git a/src/libtomahawk/Pipeline.h b/src/libtomahawk/Pipeline.h index 542298a3f..818c22d16 100644 --- a/src/libtomahawk/Pipeline.h +++ b/src/libtomahawk/Pipeline.h @@ -90,8 +90,8 @@ signals: void idle(); void resolving( const Tomahawk::query_ptr& query ); - void resolverAdded( Resolver* ); - void resolverRemoved( Resolver* ); + void resolverAdded( Tomahawk::Resolver* ); + void resolverRemoved( Tomahawk::Resolver* ); private slots: void timeoutShunt( const query_ptr& q ); From 530a420fb4517934776b41e0bcceae5b1cc1c116 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 10:41:26 +0200 Subject: [PATCH 306/433] * Tomahawk::Result now keeps track of the originating resolver and maintains a proper online state. --- src/libtomahawk/Result.cpp | 53 ++++++++++++++++++++++++++++++-------- src/libtomahawk/Result.h | 8 ++++++ 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/libtomahawk/Result.cpp b/src/libtomahawk/Result.cpp index c3ceaddcf..62e204058 100644 --- a/src/libtomahawk/Result.cpp +++ b/src/libtomahawk/Result.cpp @@ -20,7 +20,9 @@ #include "Album.h" #include "Collection.h" +#include "Resolver.h" #include "Source.h" +#include "Pipeline.h" #include "database/Database.h" #include "database/DatabaseCommand_Resolve.h" #include "database/DatabaseCommand_AllTracks.h" @@ -72,6 +74,7 @@ Result::Result( const QString& url ) , m_trackId( 0 ) , m_fileId( 0 ) { + connect( Pipeline::instance(), SIGNAL( resolverRemoved( Tomahawk::Resolver* ) ), SLOT( onResolverRemoved( Tomahawk::Resolver* ) ), Qt::QueuedConnection ); } @@ -94,12 +97,24 @@ Result::deleteLater() } +void +Result::onResolverRemoved( Tomahawk::Resolver* resolver ) +{ + if ( m_resolvedBy.data() == resolver ) + { + m_resolvedBy.clear(); + emit statusChanged(); + } +} + + artist_ptr Result::artist() const { return m_artist; } + artist_ptr Result::composer() const { @@ -124,18 +139,10 @@ Result::collection() const float Result::score() const { - if ( !collection().isNull() && collection()->source()->isOnline() ) - { + if ( isOnline() ) return m_score; - } else - { - // check if this a valid collection-less result (e.g. from youtube, but ignore offline sources still) - if ( collection().isNull() ) - return m_score; - else - return 0.0; - } + return 0.0; } @@ -152,7 +159,14 @@ Result::id() const bool Result::isOnline() const { - return ( ( !collection().isNull() && collection()->source()->isOnline() ) || collection().isNull() ); + if ( !collection().isNull() ) + { + return collection()->source()->isOnline(); + } + else + { + return !m_resolvedBy.isNull(); + } } @@ -274,3 +288,20 @@ Result::friendlySource() const else return collection()->source()->friendlyName(); } + + +Tomahawk::Resolver* +Result::resolvedBy() const +{ + if ( m_resolvedBy.isNull() ) + return 0; + + return m_resolvedBy.data(); +} + + +void +Result::setResolvedBy( Tomahawk::Resolver* resolver ) +{ + m_resolvedBy = QWeakPointer< Tomahawk::Resolver >( resolver ); +} diff --git a/src/libtomahawk/Result.h b/src/libtomahawk/Result.h index bfa6ded64..89a799e4e 100644 --- a/src/libtomahawk/Result.h +++ b/src/libtomahawk/Result.h @@ -36,6 +36,8 @@ class DatabaseCommand_LoadFile; namespace Tomahawk { +class Resolver; + class DLLEXPORT Result : public QObject { Q_OBJECT @@ -54,6 +56,9 @@ public: QString toString() const; Tomahawk::query_ptr toQuery(); + Tomahawk::Resolver* resolvedBy() const; + void setResolvedBy( Tomahawk::Resolver* resolver ); + float score() const; RID id() const; bool isOnline() const; @@ -110,6 +115,8 @@ signals: private slots: void onOffline(); void onOnline(); + + void onResolverRemoved( Tomahawk::Resolver* resolver ); private: // private constructor @@ -121,6 +128,7 @@ private: mutable RID m_rid; collection_ptr m_collection; Tomahawk::query_ptr m_query; + QWeakPointer< Tomahawk::Resolver > m_resolvedBy; Tomahawk::artist_ptr m_artist; Tomahawk::album_ptr m_album; From 07660c3f8179a186a9c8b69fb147a8c2ba87112b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 10:42:40 +0200 Subject: [PATCH 307/433] * Refresh results when the solve status changed. --- src/libtomahawk/Query.cpp | 18 ++---------------- src/libtomahawk/Query.h | 3 --- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index 246664450..4d803f776 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -125,10 +125,7 @@ Query::Query( const QString& artist, const QString& track, const QString& album, connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection ); } - connect( Pipeline::instance(), SIGNAL( resolverAdded( Resolver* ) ), - SLOT( onResolverAdded() ), Qt::QueuedConnection ); - connect( Pipeline::instance(), SIGNAL( resolverRemoved( Resolver* ) ), - SLOT( onResolverRemoved() ), Qt::QueuedConnection ); + connect( Pipeline::instance(), SIGNAL( resolverAdded( Tomahawk::Resolver* ) ), SLOT( onResolverAdded() ), Qt::QueuedConnection ); } @@ -216,7 +213,6 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) m_results << newresults; qStableSort( m_results.begin(), m_results.end(), Query::resultSorter ); - query_ptr q = m_ownRef.toStrongRef(); // hook up signals, and check solved status foreach( const result_ptr& rp, newresults ) @@ -318,16 +314,6 @@ Query::onResolverAdded() } -void -Query::onResolverRemoved() -{ - if ( !solved() ) - { - refreshResults(); - } -} - - QList< result_ptr > Query::results() const { @@ -447,7 +433,7 @@ Query::checkResults() } } - if ( m_playable && !playable ) + if ( m_solved && !solved ) { refreshResults(); } diff --git a/src/libtomahawk/Query.h b/src/libtomahawk/Query.h index 20e9956d7..6eb60088c 100644 --- a/src/libtomahawk/Query.h +++ b/src/libtomahawk/Query.h @@ -199,10 +199,7 @@ public slots: void addArtists( const QList< Tomahawk::artist_ptr >& ); void onResolvingFinished(); - - // resolve if not solved() void onResolverAdded(); - void onResolverRemoved(); private slots: void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); From f89f119078eb2b9c93f8b83995bc9281bed2c408 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 10:43:26 +0200 Subject: [PATCH 308/433] * Notify results about their originating resolver. --- src/libtomahawk/database/DatabaseResolver.cpp | 5 ++++- src/libtomahawk/resolvers/QtScriptResolver.cpp | 9 +++++++-- src/libtomahawk/resolvers/ScriptResolver.cpp | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/database/DatabaseResolver.cpp b/src/libtomahawk/database/DatabaseResolver.cpp index dcdd3816a..f7791c616 100644 --- a/src/libtomahawk/database/DatabaseResolver.cpp +++ b/src/libtomahawk/database/DatabaseResolver.cpp @@ -54,7 +54,10 @@ DatabaseResolver::resolve( const Tomahawk::query_ptr& query ) void DatabaseResolver::gotResults( const Tomahawk::QID qid, QList< Tomahawk::result_ptr> results ) { - qDebug() << Q_FUNC_INFO << qid << results.length(); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << qid << results.length(); + + foreach ( const Tomahawk::result_ptr& r, results ) + r->setResolvedBy( this ); Tomahawk::Pipeline::instance()->reportResults( qid, results ); } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index ca40016c0..b99a8e3cf 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -131,6 +131,7 @@ QtScriptResolverHelper::setResolverConfig( const QVariantMap& config ) m_resolverConfig = config; } + QString QtScriptResolverHelper::hmac( const QByteArray& key, const QByteArray &input ) { @@ -156,6 +157,7 @@ QtScriptResolverHelper::hmac( const QByteArray& key, const QByteArray &input ) #endif } + QString QtScriptResolverHelper::md5( const QByteArray& input ) { @@ -163,6 +165,7 @@ QtScriptResolverHelper::md5( const QByteArray& input ) return QString::fromLatin1( digest.toHex() ); } + void QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ) { @@ -172,6 +175,7 @@ QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QStr m_urlCallback = callbackFuncName; } + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { @@ -253,6 +257,7 @@ QtScriptResolver::running() const return m_ready && !m_stopped; } + void QtScriptResolver::reload() { @@ -362,8 +367,7 @@ QtScriptResolver::resolve( const Tomahawk::query_ptr& query ) } QVariantMap m = m_engine->mainFrame()->evaluateJavaScript( eval ).toMap(); - - if( m.isEmpty() ) + if ( m.isEmpty() ) { // if the resolver doesn't return anything, async api is used return; @@ -423,6 +427,7 @@ QtScriptResolver::parseResultVariantList( const QVariantList& reslist ) Q_ASSERT( !rp->mimetype().isEmpty() ); } + rp->setResolvedBy( this ); results << rp; } diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 009dc401e..2392c5893 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -288,6 +288,7 @@ ScriptResolver::handleMsg( const QByteArray& msg ) Q_ASSERT( !rp->mimetype().isEmpty() ); } + rp->setResolvedBy( this ); results << rp; } From f5aeeeb9c82a80e9bea4845b4f0efa5fad7e9371 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 11:24:20 +0200 Subject: [PATCH 309/433] * OverlayWidget uses PlaylistView as an event-filter for Drag-n-Drop events. --- src/libtomahawk/playlist/PlaylistView.cpp | 32 +++++++++++++++++++++++ src/libtomahawk/playlist/PlaylistView.h | 1 + src/libtomahawk/widgets/OverlayWidget.cpp | 3 +++ 3 files changed, 36 insertions(+) diff --git a/src/libtomahawk/playlist/PlaylistView.cpp b/src/libtomahawk/playlist/PlaylistView.cpp index 5c8527754..ef62eca80 100644 --- a/src/libtomahawk/playlist/PlaylistView.cpp +++ b/src/libtomahawk/playlist/PlaylistView.cpp @@ -97,6 +97,38 @@ PlaylistView::keyPressEvent( QKeyEvent* event ) } +bool +PlaylistView::eventFilter( QObject* obj, QEvent* event ) +{ + if ( event->type() == QEvent::DragEnter ) + { + QDragEnterEvent* e = static_cast(event); + dragEnterEvent( e ); + return true; + } + if ( event->type() == QEvent::DragMove ) + { + QDragMoveEvent* e = static_cast(event); + dragMoveEvent( e ); + return true; + } + if ( event->type() == QEvent::DragLeave ) + { + QDragLeaveEvent* e = static_cast(event); + dragLeaveEvent( e ); + return true; + } + if ( event->type() == QEvent::Drop ) + { + QDropEvent* e = static_cast(event); + dropEvent( e ); + return true; + } + + return QObject::eventFilter( obj, event ); +} + + void PlaylistView::deleteItems() { diff --git a/src/libtomahawk/playlist/PlaylistView.h b/src/libtomahawk/playlist/PlaylistView.h index 48d7c6892..14140f4ad 100644 --- a/src/libtomahawk/playlist/PlaylistView.h +++ b/src/libtomahawk/playlist/PlaylistView.h @@ -50,6 +50,7 @@ signals: protected: void keyPressEvent( QKeyEvent* event ); + bool eventFilter( QObject* obj, QEvent* event ); private slots: void onMenuTriggered( int action ); diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index be455af57..d3e896d64 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -66,6 +66,9 @@ OverlayWidget::~OverlayWidget() void OverlayWidget::init() { + installEventFilter( m_parent ); + setAcceptDrops( true ); + setAttribute( Qt::WA_TranslucentBackground, true ); m_opacity = 0.00; setOpacity( m_opacity ); From 5f473a0c5c892b4fe515f6f7a0a82c065b673fcd Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 12:15:38 +0200 Subject: [PATCH 310/433] * Support loading and cache artists' biographies in Artist object directly. --- src/libtomahawk/Artist.cpp | 46 ++++++++++++++++++++++++++++++++++++++ src/libtomahawk/Artist.h | 5 +++++ 2 files changed, 51 insertions(+) diff --git a/src/libtomahawk/Artist.cpp b/src/libtomahawk/Artist.cpp index 1a85915ad..ba44cda76 100644 --- a/src/libtomahawk/Artist.cpp +++ b/src/libtomahawk/Artist.cpp @@ -85,6 +85,7 @@ Artist::Artist( unsigned int id, const QString& name ) , m_coverLoaded( false ) , m_coverLoading( false ) , m_simArtistsLoaded( false ) + , m_biographyLoaded( false ) , m_infoJobs( 0 ) #ifndef ENABLE_HEADLESS , m_cover( 0 ) @@ -191,6 +192,35 @@ Artist::similarArtists() const } +QString +Artist::biography() const +{ + if ( !m_biographyLoaded ) + { + Tomahawk::InfoSystem::InfoRequestData requestData; + requestData.caller = infoid(); + requestData.customData = QVariantMap(); + + requestData.input = name(); + requestData.type = Tomahawk::InfoSystem::InfoArtistBiography; + requestData.requestId = TomahawkUtils::infosystemRequestId(); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( finished( QString ) ), + SLOT( infoSystemFinished( QString ) ), Qt::UniqueConnection ); + + m_infoJobs++; + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); + } + + return m_biography; +} + + void Artist::loadStats() { @@ -313,6 +343,22 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari break; } + case InfoSystem::InfoArtistBiography: + { + QVariantMap bmap = output.toMap(); + + foreach ( const QString& source, bmap.keys() ) + { + if ( source == "last.fm" ) + m_biography = bmap[ source ].toHash()[ "text" ].toString(); + } + + m_biographyLoaded = true; + emit biographyLoaded(); + + break; + } + default: Q_ASSERT( false ); } diff --git a/src/libtomahawk/Artist.h b/src/libtomahawk/Artist.h index deeb2fb21..3eef077a1 100644 --- a/src/libtomahawk/Artist.h +++ b/src/libtomahawk/Artist.h @@ -59,6 +59,8 @@ public: QList< Tomahawk::PlaybackLog > playbackHistory( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ) const; void setPlaybackHistory( const QList< Tomahawk::PlaybackLog >& playbackData ); unsigned int playbackCount( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ); + + QString biography() const; #ifndef ENABLE_HEADLESS QPixmap cover( const QSize& size, bool forceLoad = true ) const; @@ -77,6 +79,7 @@ signals: void updated(); void coverChanged(); void similarArtistsLoaded(); + void biographyLoaded(); void statsLoaded(); private slots: @@ -98,6 +101,7 @@ private: mutable bool m_coverLoading; QHash m_albumsLoaded; bool m_simArtistsLoaded; + bool m_biographyLoaded; mutable QString m_uuid; mutable int m_infoJobs; @@ -105,6 +109,7 @@ private: QList m_databaseAlbums; QList m_officialAlbums; QList m_similarArtists; + QString m_biography; bool m_playbackHistoryLoaded; QList< PlaybackLog > m_playbackHistory; From 145d95166d018b6f8aec9586d9f2883313950314 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 12:16:33 +0200 Subject: [PATCH 311/433] * Got rid of all direct InfoSystem calls from ArtistInfoWidget. --- .../widgets/infowidgets/ArtistInfoWidget.cpp | 62 +++---------------- .../widgets/infowidgets/ArtistInfoWidget.h | 4 +- 2 files changed, 9 insertions(+), 57 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index fe4edaa9d..8bbcda7bb 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -44,7 +44,6 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* : QWidget( parent ) , ui( new Ui::ArtistInfoWidget ) , m_artist( artist ) - , m_infoId( uuid() ) { ui->setupUi( this ); @@ -76,10 +75,6 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* connect( m_albumsModel, SIGNAL( loadingStarted() ), SLOT( onLoadingStarted() ) ); connect( m_albumsModel, SIGNAL( loadingFinished() ), SLOT( onLoadingFinished() ) ); - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - load( artist ); } @@ -148,6 +143,7 @@ ArtistInfoWidget::load( const artist_ptr& artist ) { disconnect( m_artist.data(), SIGNAL( updated() ), this, SLOT( onArtistImageUpdated() ) ); disconnect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), this, SLOT( onSimilarArtistsLoaded() ) ); + disconnect( m_artist.data(), SIGNAL( biographyLoaded() ), this, SLOT( onBiographyLoaded() ) ); disconnect( m_artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), this, SLOT( onAlbumsFound( QList, Tomahawk::ModelMode ) ) ); disconnect( m_artist.data(), SIGNAL( tracksAdded( QList, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ), @@ -157,6 +153,7 @@ ArtistInfoWidget::load( const artist_ptr& artist ) m_artist = artist; m_title = artist->name(); + connect( m_artist.data(), SIGNAL( biographyLoaded() ), SLOT( onBiographyLoaded() ) ); connect( m_artist.data(), SIGNAL( similarArtistsLoaded() ), SLOT( onSimilarArtistsLoaded() ) ); connect( m_artist.data(), SIGNAL( updated() ), SLOT( onArtistImageUpdated() ) ); connect( m_artist.data(), SIGNAL( albumsAdded( QList, Tomahawk::ModelMode ) ), @@ -172,21 +169,11 @@ ArtistInfoWidget::load( const artist_ptr& artist ) if ( !m_artist->similarArtists().isEmpty() ) onSimilarArtistsLoaded(); + + if ( !m_artist->biography().isEmpty() ) + onBiographyLoaded(); onArtistImageUpdated(); - - Tomahawk::InfoSystem::InfoStringHash artistInfo; - artistInfo["artist"] = artist->name(); - - Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.caller = m_infoId; - requestData.customData = QVariantMap(); - - requestData.input = artist->name(); - requestData.type = Tomahawk::InfoSystem::InfoArtistBiography; - Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); - - requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); } @@ -216,43 +203,10 @@ ArtistInfoWidget::onSimilarArtistsLoaded() void -ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +ArtistInfoWidget::onBiographyLoaded() { - if ( requestData.caller != m_infoId ) - return; - - InfoSystem::InfoStringHash trackInfo; - trackInfo = requestData.input.value< InfoSystem::InfoStringHash >(); - - if ( output.canConvert< QVariantMap >() ) - { - const QString artist = requestData.input.toString(); - if ( trackInfo["artist"] != m_artist->name() && artist != m_artist->name() ) - { - qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name(); - return; - } - } - - QVariantMap returnedData = output.value< QVariantMap >(); - switch ( requestData.type ) - { - case InfoSystem::InfoArtistBiography: - { - QVariantMap bmap = output.toMap(); - - foreach ( const QString& source, bmap.keys() ) - { - if ( m_longDescription.isEmpty() || source == "last.fm" ) - m_longDescription = bmap[ source ].toHash()[ "text" ].toString(); - } - emit longDescriptionChanged( m_longDescription ); - break; - } - - default: - return; - } + m_longDescription = m_artist->biography(); + emit longDescriptionChanged( m_longDescription ); } diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index 17477da1a..6c00ab0f2 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -35,7 +35,6 @@ #include "Typedefs.h" #include "PlaylistInterface.h" #include "ViewPage.h" -#include "infosystem/InfoSystem.h" #include "DllMacro.h" @@ -90,8 +89,8 @@ protected: void changeEvent( QEvent* e ); private slots: - void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); void onArtistImageUpdated(); + void onBiographyLoaded(); void onAlbumsFound( const QList& albums, Tomahawk::ModelMode mode ); void onTracksFound( const QList& queries, Tomahawk::ModelMode mode ); @@ -113,7 +112,6 @@ private: QString m_title; QString m_description; QString m_longDescription; - QString m_infoId; QPixmap m_pixmap; friend class MetaPlaylistInterface; From 197dda1ff78075917fcfa0acb2badeed230e4006 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 13:01:02 +0200 Subject: [PATCH 312/433] * Set default vertical alignment for QueryLabels to be centered. --- src/libtomahawk/widgets/QueryLabel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/QueryLabel.cpp b/src/libtomahawk/widgets/QueryLabel.cpp index d81e32843..82b40d084 100644 --- a/src/libtomahawk/widgets/QueryLabel.cpp +++ b/src/libtomahawk/widgets/QueryLabel.cpp @@ -89,7 +89,7 @@ QueryLabel::init() m_useCustomPen = false; m_useCustomFont = false; - m_align = Qt::AlignLeft; + m_align = Qt::AlignLeft | Qt::AlignVCenter; m_mode = Qt::ElideMiddle; } From f174afbd567c921111ea1fb5dcafc9807c5461f0 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 13:07:11 +0200 Subject: [PATCH 313/433] * Make artist & album names clickable on track page. --- .../widgets/infowidgets/TrackInfoWidget.cpp | 26 +++++++++++++++++-- .../widgets/infowidgets/TrackInfoWidget.h | 3 +++ .../widgets/infowidgets/TrackInfoWidget.ui | 9 +++++-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 893642628..20837b978 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -37,6 +37,7 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par , ui( new Ui::TrackInfoWidget ) { ui->setupUi( this ); + QPalette pal = palette(); pal.setColor( QPalette::Window, QColor( "#323435" ) ); @@ -83,6 +84,9 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->lyricsView->setPalette( p ); // ui->similarTracksLabel->setPalette( p ); + ui->artistLabel->setType( QueryLabel::Artist ); + ui->albumLabel->setType( QueryLabel::Album ); + m_relatedTracksModel = new PlayableModel( ui->similarTracksView ); ui->similarTracksView->setPlayableModel( m_relatedTracksModel ); ui->similarTracksView->proxyModel()->sort( -1 ); @@ -91,6 +95,9 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); load( query ); + + connect( ui->artistLabel, SIGNAL( clickedArtist() ), SLOT( onArtistClicked() ) ); + connect( ui->albumLabel, SIGNAL( clickedAlbum() ), SLOT( onAlbumClicked() ) ); } @@ -150,8 +157,8 @@ TrackInfoWidget::load( const query_ptr& query ) onCoverUpdated(); ui->trackLabel->setText( query->track() ); - ui->artistLabel->setText( query->artist() ); - ui->albumLabel->setText( query->album() ); + ui->artistLabel->setQuery( query ); + ui->albumLabel->setQuery( query ); ui->fromLabel->setVisible( !query->album().isEmpty() ); m_relatedTracksModel->clear(); @@ -223,6 +230,21 @@ TrackInfoWidget::onLyricsLoaded() } +void +TrackInfoWidget::onArtistClicked() +{ + ViewManager::instance()->show( Artist::get( m_query->artist(), false ) ); +} + + +void +TrackInfoWidget::onAlbumClicked() +{ + artist_ptr artist = Artist::get( m_query->artist(), false ); + ViewManager::instance()->show( Album::get( artist, m_query->album(), false ) ); +} + + void TrackInfoWidget::changeEvent( QEvent* e ) { diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h index 93c82b61d..dc9c3de64 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.h @@ -82,6 +82,9 @@ private slots: void onSimilarTracksLoaded(); void onLyricsLoaded(); + void onArtistClicked(); + void onAlbumClicked(); + private: Ui::TrackInfoWidget *ui; diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui index 8aeba01e2..088f5b234 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui @@ -83,7 +83,7 @@ - + Artist @@ -107,7 +107,7 @@ - + Album @@ -233,6 +233,11 @@ QLabel
    widgets/HeaderLabel.h
    + + QueryLabel + QLabel +
    widgets/QueryLabel.h
    +
    From 7dabdc0a6822e38b07c090f2ad98b299c8719f94 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 13:25:02 +0200 Subject: [PATCH 314/433] * Make FuzzyIndex robuster. --- src/libtomahawk/database/FuzzyIndex.cpp | 44 ++++++++++++++++++------- src/libtomahawk/database/FuzzyIndex.h | 7 +++- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/libtomahawk/database/FuzzyIndex.cpp b/src/libtomahawk/database/FuzzyIndex.cpp index a6a117ffc..017e1bb4b 100644 --- a/src/libtomahawk/database/FuzzyIndex.cpp +++ b/src/libtomahawk/database/FuzzyIndex.cpp @@ -24,7 +24,9 @@ #include #include +#include "DatabaseCommand_UpdateSearchIndex.h" #include "DatabaseImpl.h" +#include "Database.h" #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "Source.h" @@ -38,7 +40,7 @@ using namespace lucene::queryParser; using namespace lucene::search; -FuzzyIndex::FuzzyIndex( QObject* parent, bool wipeIndex ) +FuzzyIndex::FuzzyIndex( QObject* parent, bool wipe ) : QObject( parent ) , m_luceneReader( 0 ) , m_luceneSearcher( 0 ) @@ -56,15 +58,11 @@ FuzzyIndex::FuzzyIndex( QObject* parent, bool wipeIndex ) catch ( CLuceneError& error ) { tDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + wipe = true; } - if ( wipeIndex ) - { - tLog( LOGVERBOSE ) << "Wiping fuzzy index..."; - beginIndexing(); - endIndexing(); - } + if ( wipe ) + wipeIndex(); } @@ -77,6 +75,27 @@ FuzzyIndex::~FuzzyIndex() } +bool +FuzzyIndex::wipeIndex() +{ + tLog( LOGVERBOSE ) << "Wiping fuzzy index..."; + beginIndexing(); + endIndexing(); + + QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); + + return true; // FIXME +} + + +void +FuzzyIndex::updateIndex() +{ + DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + + void FuzzyIndex::beginIndexing() { @@ -170,7 +189,8 @@ FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >& catch( CLuceneError& error ) { tDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + + wipeIndex(); } } @@ -263,7 +283,8 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query ) catch( CLuceneError& error ) { tDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + + wipeIndex(); } return resultsmap; @@ -317,7 +338,8 @@ FuzzyIndex::searchAlbum( const Tomahawk::query_ptr& query ) catch( CLuceneError& error ) { tDebug() << "Caught CLucene error:" << error.what(); - Q_ASSERT( false ); + + wipeIndex(); } return resultsmap; diff --git a/src/libtomahawk/database/FuzzyIndex.h b/src/libtomahawk/database/FuzzyIndex.h index f6da1aa76..e1f0be693 100644 --- a/src/libtomahawk/database/FuzzyIndex.h +++ b/src/libtomahawk/database/FuzzyIndex.h @@ -55,7 +55,7 @@ class FuzzyIndex : public QObject Q_OBJECT public: - explicit FuzzyIndex( QObject* parent, bool wipeIndex = false ); + explicit FuzzyIndex( QObject* parent, bool wipe = false ); ~FuzzyIndex(); void beginIndexing(); @@ -71,7 +71,12 @@ public slots: QMap< int, float > search( const Tomahawk::query_ptr& query ); QMap< int, float > searchAlbum( const Tomahawk::query_ptr& query ); +private slots: + void updateIndex(); + private: + bool wipeIndex(); + QMutex m_mutex; QString m_lucenePath; From 2389770d8a0e3b6acaca67b990165a49a21342e4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 13:25:33 +0200 Subject: [PATCH 315/433] * Moved reindexing to FuzzyIndex. --- src/libtomahawk/database/DatabaseImpl.cpp | 11 ----------- src/libtomahawk/database/DatabaseImpl.h | 3 --- 2 files changed, 14 deletions(-) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 1119f58a8..ff65e8cc5 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -27,7 +27,6 @@ #include #include "database/Database.h" -#include "DatabaseCommand_UpdateSearchIndex.h" #include "SourceList.h" #include "Result.h" #include "Artist.h" @@ -75,8 +74,6 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent ) query.exec( "UPDATE source SET isonline = 'false'" ); m_fuzzyIndex = new FuzzyIndex( this, schemaUpdated ); - if ( schemaUpdated ) - QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); tDebug( LOGVERBOSE ) << "Loaded index:" << t.elapsed(); if ( qApp->arguments().contains( "--dumpdb" ) ) @@ -774,11 +771,3 @@ DatabaseImpl::openDatabase( const QString& dbname, bool checkSchema ) return schemaUpdated; } - - -void -DatabaseImpl::updateIndex() -{ - DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex(); - Database::instance()->enqueue( QSharedPointer( cmd ) ); -} diff --git a/src/libtomahawk/database/DatabaseImpl.h b/src/libtomahawk/database/DatabaseImpl.h index 671c86018..9dfe213e5 100644 --- a/src/libtomahawk/database/DatabaseImpl.h +++ b/src/libtomahawk/database/DatabaseImpl.h @@ -81,9 +81,6 @@ public: signals: void indexReady(); -private slots: - void updateIndex(); - private: DatabaseImpl( Database* parent, const QString& dbname ); void setFuzzyIndex( FuzzyIndex* fi ) { m_fuzzyIndex = fi; } From aadd7fea2b57454925314a30b91d8aa9cf3e041f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 13:32:54 +0200 Subject: [PATCH 316/433] * Prevent race condition when cloning DatabaseImpls. --- src/libtomahawk/database/DatabaseImpl.cpp | 2 ++ src/libtomahawk/database/DatabaseImpl.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index ff65e8cc5..4648a988a 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -131,6 +131,8 @@ DatabaseImpl::~DatabaseImpl() DatabaseImpl* DatabaseImpl::clone() const { + QMutexLocker lock( &m_mutex ); + DatabaseImpl* impl = new DatabaseImpl( m_parent, m_db.databaseName() ); impl->setDatabaseID( m_dbid ); impl->setFuzzyIndex( m_fuzzyIndex ); diff --git a/src/libtomahawk/database/DatabaseImpl.h b/src/libtomahawk/database/DatabaseImpl.h index 9dfe213e5..47b921d33 100644 --- a/src/libtomahawk/database/DatabaseImpl.h +++ b/src/libtomahawk/database/DatabaseImpl.h @@ -101,6 +101,7 @@ private: QString m_dbid; FuzzyIndex* m_fuzzyIndex; + mutable QMutex m_mutex; }; #endif // DATABASEIMPL_H From 1272973b52d40795eb9952f92a3f995f8e0198e7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 14:11:18 +0200 Subject: [PATCH 317/433] * Make sure Phonon errors show up on console, and not just the log file. --- src/libtomahawk/audio/AudioEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 75f2748ee..755875614 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -684,7 +684,7 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) { stop( UnknownError ); - tLog() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType(); + tDebug() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType(); emit error( UnknownError ); setState( Error ); From 8d125f128cef3cbc69d6f7397248ab81d1acb227 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 14:12:17 +0200 Subject: [PATCH 318/433] * Send version string along when requesting providers.xml from server. --- src/libtomahawk/AtticaManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp index 099ca09c2..f0782b4d3 100644 --- a/src/libtomahawk/AtticaManager.cpp +++ b/src/libtomahawk/AtticaManager.cpp @@ -42,6 +42,7 @@ using namespace Attica; AtticaManager* AtticaManager::s_instance = 0; + // Sort binary resolvers above script resolvers, and script resolvers by download count bool resolverSort( const Attica::Content& first, const Attica::Content& second ) @@ -52,6 +53,7 @@ resolverSort( const Attica::Content& first, const Attica::Content& second ) return first.downloads() > second.downloads(); } + AtticaManager::AtticaManager( QObject* parent ) : QObject( parent ) , m_resolverJobsLoaded( 0 ) @@ -60,7 +62,9 @@ AtticaManager::AtticaManager( QObject* parent ) // resolvers // m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ); - QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) ) ); + + const QString url = QString( "http://bakery.tomahawk-player.org/resolvers/providers.xml?version=%1" ).arg( TomahawkUtils::appFriendlyVersion() ); + QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( url ) ) ); NewClosure( reply, SIGNAL( finished() ), this, SLOT( providerFetched( QNetworkReply* ) ), reply ); connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( providerError( QNetworkReply::NetworkError ) ) ); From 171f0e314b2781f41de9f4542015c78c288e8536 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 7 Jun 2012 14:35:49 +0200 Subject: [PATCH 319/433] * Keep retrying on commit transaction locks. --- src/libtomahawk/database/TomahawkSqlQuery.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/database/TomahawkSqlQuery.cpp b/src/libtomahawk/database/TomahawkSqlQuery.cpp index b57274b6e..aa75fc9e5 100644 --- a/src/libtomahawk/database/TomahawkSqlQuery.cpp +++ b/src/libtomahawk/database/TomahawkSqlQuery.cpp @@ -102,7 +102,7 @@ TomahawkSqlQuery::commitTransaction() if ( isBusyError( lastError() ) ) retries = 0; - tDebug() << "INFO: Retrying failed commit:" << lastQuery() << lastError().text(); + tDebug() << "INFO: Retrying failed commit:" << retries << lastQuery() << lastError().text(); TomahawkUtils::msleep( 10 ); } @@ -125,7 +125,7 @@ TomahawkSqlQuery::showError() bool TomahawkSqlQuery::isBusyError( const QSqlError& error ) const { - const QString text = error.text().toLower(); + const QString text = error.text().trimmed().toLower(); - return ( text.contains( "locked" ) || text.contains( "busy" ) ); + return ( text.contains( "locked" ) || text.contains( "busy" ) || text.isEmpty() ); } From 658f919104d8bc59c3994eb5e742476d313de5d3 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Thu, 7 Jun 2012 22:16:55 +0000 Subject: [PATCH 320/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_bg.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_ca.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_de.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_en.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_es.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_fr.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_ja.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_pl.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_pt_BR.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_ru.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_sv.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_tr.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_zh_CN.ts | 130 ++++++++++++++++++++--------------------- lang/tomahawk_zh_TW.ts | 130 ++++++++++++++++++++--------------------- 15 files changed, 975 insertions(+), 975 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index f90629ba0..15a2091f4 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -186,17 +186,17 @@ connect and stream from you? ألبومات - + Sorry, we could not find any albums for this artist! نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! - + Sorry, we could not find any related artists! نعتذر، لم نستطيع إيجاد فنانين! - + Sorry, we could not find any top hits for this artist! نعتذر، لم نستطيع إيجاد أغاني مشهورة جدا لهذا الفنان! @@ -771,12 +771,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. هذه المجموعة فارغة حاليا. - + This playlist is currently empty. Add some tracks to it and enjoy the music! هذه القائمة فارغة حاليا. أضف لها بعض الأغاني واستمتع للموسيقى! @@ -845,67 +845,67 @@ connect and stream from you? QObject - + %n year(s) ago منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - + %n year(s) منذ %n سنةمنذ سنة %nمنذ سنتين %nمنذ %n سنواتمنذ %n سنواتمنذ %n سنوات - + %n month(s) ago منذ %n شهرمنذ شهر %nمنذ شهرين %nمنذ %n أشهرمنذ %n أشهرمنذ %n أشهر - + %n month(s) منذ %n شهرمنذ شهر %nمنذ شهرين %nمنذ %n أشهرمنذ %n أشهرمنذ %n أشهر - + %n week(s) ago منذ %n أسبوعمنذ أسبوع %nمنذ أسبوعين %nمنذ %n أسابيعمنذ %n أسابيعمنذ %n أسابيع - + %n week(s) منذ %n أسبوعمنذ أسبوع %nمنذ أسبوعين %nمنذ %n أسابيعمنذ %n أسابيعمنذ %n أسابيع - + %n day(s) ago منذ %n يوممنذ يوم %nمنذ يومين %nمنذ %n أياممنذ %n أياممنذ %n أيام - + %n day(s) منذ %n يوممنذ يوم %nمنذ يومين %nمنذ %n أياممنذ %n أياممنذ %n أيام - + %n hour(s) ago منذ %n ساعةمنذ ساعة %nمنذ ساعتين %nمنذ %n ساعاتمنذ %n ساعاتمنذ %n ساعات - + %n hour(s) منذ %n ساعةمنذ ساعة %nمنذ ساعتين %nمنذ %n ساعاتمنذ %n ساعاتمنذ %n ساعات - + %1 minutes ago منذ %1 دقائق - + %1 minutes %1 دقائق - + just now الآن @@ -1130,30 +1130,20 @@ connect and stream from you? Top 10 توب ١٠ - - - Offline - غير متصل - All available tracks جميع الأغاني المتاحة - - Online - متصل - - - - + + Show أظهر - - + + Hide إخفي @@ -1200,7 +1190,7 @@ connect and stream from you? - + Latest Additions أحدث الإضافات @@ -1215,47 +1205,47 @@ connect and stream from you? الأغاني المحبوبة - + SuperCollection سوبر كولكشن - + Sorry, we could not find any loved tracks! نعتذر، لم نستطيع إيجاد أغاني محبوبة! - + Latest additions to your collection آخر إضافات على مجموعتك - + Latest additions to %1's collection آخر إضافات على مجموعة %1 - + Sorry, we could not find any recent additions! نعتذر، لم نستطيع إيجاد إضافة جديدة! - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Your recently played tracks الأغاني التي إستمعت إليها مؤخرا - + %1's recently played tracks الأغاني التي سمعها مؤخرا %1 - + Sorry, we could not find any recent plays! نعتذر، لم نستطيع إيجاد أغاني مسموعة مؤخرا! @@ -2694,37 +2684,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and و - + You أنت - + you أنت - + and و - + %n other(s) %n أخرين%n أخر%n أخرين%n أخرين%n أخرين%n أخرين - + %1 people %1 أشخاص - + loved this track أحببت هذه الأغنية @@ -2748,36 +2738,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) يجري مسح (%L1 أغنية) - + Scanning مسح - + Checking فحص - + Fetching جلب - + Parsing تحليل - + Saving (%1%) تحفيظ(%1%) + + + Online + متصل + + + + Offline + غير متصل + Tomahawk::SpotifyParser @@ -2798,7 +2798,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection مجموعتي الخاصة @@ -3320,32 +3320,32 @@ enter the displayed PIN number here: أغاني قريبة - + Sorry, but we could not find similar tracks for this song! نعتذر، لم نستطيع إيجاد أغاني قريبة من هذه الأغنية! - + You've listened to this track %n time(s). لقد استمعت إلى هذه الأغنية %n مرة.لقد استمعت إلى هذه الأغنية مرة %n.لقد استمعت إلى هذه الأغنية مرتين %n.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات. - + You've never listened to this track before. لم تستمع لهذه الأغنية من قبل. - + You first listened to it on %1. استمعت إليها أولاً في %1. - + You've listened to %1 %n time(s). لقد استمعت إلى %1 %n مرة.لقد استمعت إلى %1 مرة %n.لقد استمعت إلى %1 مرتين %n.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات. - + You've never listened to %1 before. لم تستمع إلى %1 من قبل. @@ -3536,12 +3536,12 @@ You can re-send a sync message at any time simply by sending another tweet using الأغاني التي إستمعت إليها مؤخرا - + No recently created playlists in your network. لا قوائم أغاني جديدة أنشئت مؤخرا على شبكتك. - + Welcome to Tomahawk مرحبا بكم في توماهوك diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 41f559284..eaa52a8bd 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -185,17 +185,17 @@ connect and stream from you? Албуми - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -773,12 +773,12 @@ Tomahaw създаде доклад относно това и изпращай PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Този списък в момента е празен. Добави няколко изпълнения и се наслади на музиката! @@ -845,67 +845,67 @@ Tomahaw създаде доклад относно това и изпращай QObject - + %n year(s) ago преди %n годинапреди %n години - + %n year(s) %n година%n години - + %n month(s) ago преди %n месецпреди %n месеца - + %n month(s) %n месец%n месеца - + %n week(s) ago преди %n седмицапреди %n седмици - + %n week(s) %n седмица%n седмици - + %n day(s) ago преди %n денпреди %n дена - + %n day(s) %n ден%n дена - + %n hour(s) ago преди %n часпреди %n часа - + %n hour(s) %n час %n часа - + %1 minutes ago преди %1 минути - + %1 minutes %1 минути - + just now току-що @@ -1130,30 +1130,20 @@ Tomahaw създаде доклад относно това и изпращай Top 10 Първите 10 - - - Offline - Извън линия - All available tracks Всички налични изпълнения - - Online - На линия - - - - + + Show Покажи - - + + Hide Скрий @@ -1200,7 +1190,7 @@ Tomahaw създаде доклад относно това и изпращай - + Latest Additions Последно добавени @@ -1215,48 +1205,48 @@ Tomahaw създаде доклад относно това и изпращай Харесани песни - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Последно добавени към колекцията - + Latest additions to %1's collection Последно добавени в колекцията на %1 - + Sorry, we could not find any recent additions! - + Recently Played Tracks Наскоро изпълнени песни - + Your recently played tracks Наскоро изпълнени песни от теб - + %1's recently played tracks Наскоро изпълнените песни от %1 - + Sorry, we could not find any recent plays! @@ -2701,37 +2691,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and и - + You Ти - + you ти - + and и - + %n other(s) %n друг%n други - + %1 people %1 хора - + loved this track хареса тази песен @@ -2755,36 +2745,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканиране (%L1 песни) - + Scanning Сканирам - + Checking Проверявам - + Fetching Извличам - + Parsing Сортирам - + Saving (%1%) Запазвам (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2805,7 +2805,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция @@ -3330,32 +3330,32 @@ enter the displayed PIN number here: Подобни песни - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Ти си слушал тази песен %n път(и)Ти си слушал тази песен %n път(и) - + You've never listened to this track before. Никога не си слушал тази песен преди - + You first listened to it on %1. Първоначално си я слушал на %1 - + You've listened to %1 %n time(s). Слушал си %1 път(и)Слушал си %1 %n път(и) - + You've never listened to %1 before. Никога не си слушал %1 преди @@ -3548,12 +3548,12 @@ You can re-send a sync message at any time simply by sending another tweet using Наскоро изпълнени - + No recently created playlists in your network. Не откривам наскоро създадени списъци в твоята мрежа - + Welcome to Tomahawk Здравей! diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 36fcee927..1f7558a66 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -185,17 +185,17 @@ connect and stream from you? Àlbums - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Aquesta llista es troba buida. Afegiu-hi algunes cançons i gaudiu de la música! @@ -843,67 +843,67 @@ connect and stream from you? QObject - + %n year(s) ago fa %n anyfa %n anys - + %n year(s) %n any%n anys - + %n month(s) ago fa %n mesfa %n mesos - + %n month(s) %n mes%n mesos - + %n week(s) ago fa %n setmanafa %n setmanes - + %n week(s) %n setmana%n setmanes - + %n day(s) ago fa %n diafa %n dies - + %n day(s) %n dia%n dies - + %n hour(s) ago fa %n horafa %n hores - + %n hour(s) %n hora%n hores - + %1 minutes ago fa %1 minut - + %1 minutes %1 minuts - + just now ara mateix @@ -1128,30 +1128,20 @@ connect and stream from you? Top 10 Top 10 - - - Offline - Fora de Línia - All available tracks Totes les cançons disponibles - - Online - En Línia - - - - + + Show Mostra - - + + Hide Amaga @@ -1198,7 +1188,7 @@ connect and stream from you? - + Latest Additions Darreres Novetats @@ -1213,47 +1203,47 @@ connect and stream from you? Cançons Preferides - + SuperCollection SuperCol·lecció - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Darreres novetats a la vostra col·lecció - + Latest additions to %1's collection Darreres novetats a la col·lecció de %1 - + Sorry, we could not find any recent additions! - + Recently Played Tracks Cançons Escoltades Recentment - + Your recently played tracks Cançons Escoltades Recentment - + %1's recently played tracks Cançons Escoltades Recentment per %1 - + Sorry, we could not find any recent plays! @@ -2693,37 +2683,37 @@ Intenteu ajustar els filtres per reproduir noves cançons.
    Tomahawk::Query - + and i - + You Jo - + you jo - + and i - + %n other(s) %n més%n més - + %1 people %1 persones - + loved this track els ha encantat aquesta cançó @@ -2747,36 +2737,46 @@ Intenteu ajustar els filtres per reproduir noves cançons.
    Tomahawk::Source - - + + Scanning (%L1 tracks) Escanejant (%L1 cançons) - + Scanning Escanejant - + Checking Comprovant - + Fetching Cercant - + Parsing Analitzant - + Saving (%1%) Desant (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2797,7 +2797,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. TomahawkApp - + My Collection La meva Col·lecció @@ -3319,32 +3319,32 @@ introduïu el PIN aquí: Cançons Semblants - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Heu escoltat aquesta cançó %n cop.Heu escoltat aquesta cançó %n cops. - + You've never listened to this track before. No heu escoltat mai aquesta cançó abans. - + You first listened to it on %1. Vau escoltar aquesta cançó per primer cop el %1. - + You've listened to %1 %n time(s). Heu escoltat %1 %n cop.Heu escoltat %1 %n cops. - + You've never listened to %1 before. No heu escoltat mai %1 abans. @@ -3535,12 +3535,12 @@ Podeu reenviar un missatge de sincronisme en qualsevol moment simplement enviant Cançons Escoltades Recentment - + No recently created playlists in your network. No hi ha cançons escoltades recentment a la xarxa. - + Welcome to Tomahawk Us donem la benvinguda a Tomahawk diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index d3e798d89..165b40118 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -185,17 +185,17 @@ connect and stream from you? Alben - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Diese Playliste ist derzeit leer. Füge einige Stücke hinzu und genieße die Musik! @@ -843,67 +843,67 @@ connect and stream from you? QObject - + %n year(s) ago vor %n Jahrvor %n Jahren - + %n year(s) %n Jahr%n Jahre - + %n month(s) ago vor %n Monatvor %n Monaten - + %n month(s) %n Monat%n Monate - + %n week(s) ago vor %n Wochevor %n Wochen - + %n week(s) %n Woche%n Wochen - + %n day(s) ago vor %n Tagvor %n Tagen - + %n day(s) %n Tag%n Tage - + %n hour(s) ago vor %n Stundevor %n Stunden - + %n hour(s) %n Stunde%n Stunden - + %1 minutes ago vor %1 Minuten - + %1 minutes %1 Minuten - + just now gerade eben @@ -1128,30 +1128,20 @@ connect and stream from you? Top 10 Top 10 - - - Offline - Nicht Verbunden - All available tracks Alle verfügbaren Stücke - - Online - Verbunden - - - - + + Show Einblenden - - + + Hide Verstecken @@ -1198,7 +1188,7 @@ connect and stream from you? - + Latest Additions Kürzlich hinzugekommen @@ -1213,47 +1203,47 @@ connect and stream from you? Lieblingslieder - + SuperCollection Supersammlung - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Neueste Lieder in deiner Sammlung - + Latest additions to %1's collection Neueste Lieder in %1's Sammlung - + Sorry, we could not find any recent additions! - + Recently Played Tracks Zuletzt gehörte Lieder - + Your recently played tracks Deine zuletzt gehörten Lieder - + %1's recently played tracks %1's zuletzt gehörte Lieder - + Sorry, we could not find any recent plays! @@ -2688,37 +2678,37 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Query - + and und - + You Du - + you du - + and und - + %n other(s) %n anderer%n andere - + %1 people %1 Leute - + loved this track liebte dieses Lied @@ -2742,36 +2732,46 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanne (%L1 Stücke) - + Scanning Scanne - + Checking Überprüfe - + Fetching Sammle - + Parsing Parse - + Saving (%1%) Speichere (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2792,7 +2792,7 @@ Versuch die Filter anzupassen für neue Lieder. TomahawkApp - + My Collection Meine Sammlung @@ -3314,32 +3314,32 @@ Tomahawk auf Twitter's Website authentifiziert hast: Ähnliche Lieder - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Du hast dieses Lied einmal gehört.Du hast dieses Lied %n mal gehört. - + You've never listened to this track before. Du hast dieses Lied noch nie angehört. - + You first listened to it on %1. Du hast dieses Lied zum ersten mal am %1 gehört. - + You've listened to %1 %n time(s). Du hast %1 einmal angehört.Du hast %1 %n mal angehört. - + You've never listened to %1 before. Du hast %1 vorher noch nie gehört. @@ -3525,12 +3525,12 @@ You can re-send a sync message at any time simply by sending another tweet using Kürzlich gehörte Lieder - + No recently created playlists in your network. Es gibt keine kürzlich erstellten Playlisten in deinem Netzwerk. - + Welcome to Tomahawk Willkommen bei Tomahawk diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index ffd1c8263..54c697a59 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -186,17 +186,17 @@ connect and stream from you? Albums - + Sorry, we could not find any albums for this artist! Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! Sorry, we could not find any top hits for this artist! @@ -771,12 +771,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -844,67 +844,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutes ago - + %1 minutes %1 minutes - + just now just now @@ -1129,30 +1129,20 @@ connect and stream from you? Top 10 Top 10 - - - Offline - Offline - All available tracks All available tracks - - Online - Online - - - - + + Show Show - - + + Hide Hide @@ -1199,7 +1189,7 @@ connect and stream from you? - + Latest Additions Latest Additions @@ -1214,47 +1204,47 @@ connect and stream from you? Loved Tracks - + SuperCollection SuperCollection - + Sorry, we could not find any loved tracks! Sorry, we could not find any loved tracks! - + Latest additions to your collection Latest additions to your collection - + Latest additions to %1's collection Latest additions to %1's collection - + Sorry, we could not find any recent additions! Sorry, we could not find any recent additions! - + Recently Played Tracks Recently Played Tracks - + Your recently played tracks Your recently played tracks - + %1's recently played tracks %1's recently played tracks - + Sorry, we could not find any recent plays! Sorry, we could not find any recent plays! @@ -2694,37 +2684,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and and - + You You - + you you - + and and - + %n other(s) %n other%n others - + %1 people %1 people - + loved this track loved this track @@ -2748,36 +2738,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanning (%L1 tracks) - + Scanning Scanning - + Checking Checking - + Fetching Fetching - + Parsing Parsing - + Saving (%1%) Saving (%1%) + + + Online + Online + + + + Offline + Offline + Tomahawk::SpotifyParser @@ -2798,7 +2798,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection My Collection @@ -3320,32 +3320,32 @@ enter the displayed PIN number here: Similar Tracks - + Sorry, but we could not find similar tracks for this song! Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). You've listened to this track %n time(s).You've listened to this track %n time(s). - + You've never listened to this track before. You've never listened to this track before. - + You first listened to it on %1. You first listened to it on %1. - + You've listened to %1 %n time(s). You've listened to %1 %n time(s).You've listened to %1 %n time(s). - + You've never listened to %1 before. You've never listened to %1 before. @@ -3536,12 +3536,12 @@ You can re-send a sync message at any time simply by sending another tweet using Recently Played Tracks - + No recently created playlists in your network. No recently created playlists in your network. - + Welcome to Tomahawk Welcome to Tomahawk diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 425c4a4d4..8d6ccad7e 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -185,17 +185,17 @@ connect and stream from you? Álbumes - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reproducción está vacía. ¡Añada algunas pistas y disfrute de la música! @@ -842,67 +842,67 @@ connect and stream from you? QObject - + %n year(s) ago hace %n añohace%n años - + %n year(s) %n año%n años - + %n month(s) ago hace %n meshace %n meses - + %n month(s) %n mes%n meses - + %n week(s) ago hace %n semanahace %n semanas - + %n week(s) %n semana%n semanas - + %n day(s) ago hace %n díahace %n días - + %n day(s) %n día%n días - + %n hour(s) ago hace %n horahace %n horas - + %n hour(s) %n hora%n horas - + %1 minutes ago hace %1 minutos - + %1 minutes %1 minutos - + just now justo ahora @@ -1127,30 +1127,20 @@ connect and stream from you? Top 10 Top 10 - - - Offline - Desconectado - All available tracks Todas las pistas disponibles - - Online - Conectado - - - - + + Show Mostrar - - + + Hide Ocultar @@ -1197,7 +1187,7 @@ connect and stream from you? - + Latest Additions Añadidos recientemente @@ -1212,47 +1202,47 @@ connect and stream from you? Pistas favoritas - + SuperCollection SuperColección - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Últimas novedades en mi colección - + Latest additions to %1's collection Últimas novedadoes en la colección de %1 - + Sorry, we could not find any recent additions! - + Recently Played Tracks Temas Escuchados Recientemente - + Your recently played tracks Mis canciones escuchadas recientemente - + %1's recently played tracks Las canciones escuchadas recientemente por %1 - + Sorry, we could not find any recent plays! @@ -2692,37 +2682,37 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Query - + and y - + You usted - + you usted - + and y - + %n other(s) %n más%n más - + %1 people %1 personas - + loved this track han añadido este tema a Favoritos @@ -2746,36 +2736,46 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 pistas) - + Scanning Escaneando - + Checking Comprobando - + Fetching Obteniendo - + Parsing Analizando - + Saving (%1%) Guardando (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2796,7 +2796,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. TomahawkApp - + My Collection Mi colección @@ -3318,32 +3318,32 @@ introduzca su número PIN aquí: Temas Similares - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Ha escuchado esta canción %n vez.Ha escuchado esta canción %n veces. - + You've never listened to this track before. Nunca ha escuchado este tema antes. - + You first listened to it on %1. Escuchó este tema pro primera vez en %1. - + You've listened to %1 %n time(s). Ha escuchado %1 %n vez.Ha escuchado %1 %n veces. - + You've never listened to %1 before. Nunca ha escuchado %1 antes. @@ -3534,12 +3534,12 @@ Puede reenviar el mensaje de sincronización en cualquier momento simplemente en Pistas reproducidas recientemente - + No recently created playlists in your network. No hay listas de reproducción recientemente creadas en su red. - + Welcome to Tomahawk Bienvenido a Tomahawk diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 6418697a7..d51788a0b 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -186,17 +186,17 @@ se connecter et streamer depuis chez vous ? Albums - + Sorry, we could not find any albums for this artist! Désolé, on a pas pu trouver aucun album pour cet artiste! - + Sorry, we could not find any related artists! Désolé, on a rien trouvé par rapport a cet artite! - + Sorry, we could not find any top hits for this artist! Désolé, on a pas pu trouver aucun top hit pour cet artiste! @@ -771,12 +771,12 @@ se connecter et streamer depuis chez vous ? PlaylistView - + This playlist is currently empty. La collection est vide actuellement. - + This playlist is currently empty. Add some tracks to it and enjoy the music! La liste de lecture est vide. Ajoutez des pistes et profitez de la musique ! @@ -844,67 +844,67 @@ se connecter et streamer depuis chez vous ? QObject - + %n year(s) ago il y a %n anil y a %n ans - + %n year(s) %n an%n ans - + %n month(s) ago il y a %n moisil y a %n mois - + %n month(s) %n mois%n mois - + %n week(s) ago il y a %n semaineil y a %n semaines - + %n week(s) %n semaine%n semaines - + %n day(s) ago il y a %n jouril y a %n jours - + %n day(s) %n jour%n jours - + %n hour(s) ago il y a %n heureil y a %n heures - + %n hour(s) %n heure%n heures - + %1 minutes ago il y a %1 minutes - + %1 minutes %1 minutes - + just now à l'instant @@ -1129,30 +1129,20 @@ se connecter et streamer depuis chez vous ? Top 10 Top 10 - - - Offline - Hors ligne - All available tracks Tous les titres disponibles - - Online - En Ligne - - - - + + Show Afficher - - + + Hide Masquer @@ -1199,7 +1189,7 @@ se connecter et streamer depuis chez vous ? - + Latest Additions Derniers ajouts @@ -1214,47 +1204,47 @@ se connecter et streamer depuis chez vous ? Titres favoris - + SuperCollection SuperCollection - + Sorry, we could not find any loved tracks! Désolé, on a pas pu trouver aucune piste favoris! - + Latest additions to your collection Derniers ajouts à votre collection - + Latest additions to %1's collection Derniers ajouts à la collection de %1 - + Sorry, we could not find any recent additions! Désolé, on a pas pu trouver des dernier ajouts! - + Recently Played Tracks Derniers titres joués - + Your recently played tracks Les derniers titres que vous avez joués - + %1's recently played tracks Derniers titres joués par %1 - + Sorry, we could not find any recent plays! Désolé, on a pas pu trouver aucune piste récement joués! @@ -2694,37 +2684,37 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Query - + and et - + You Vous - + you vous - + and et - + %n other(s) %n autre%n autres - + %1 people %1 personnes - + loved this track a enregistré cette piste dans ses favoris @@ -2748,36 +2738,46 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Source - - + + Scanning (%L1 tracks) Scan en cours (%L1 titres) - + Scanning Scan en cours - + Checking Vérification - + Fetching Chargement - + Parsing Décodage - + Saving (%1%) Enregistrement (%1%) + + + Online + En Ligne + + + + Offline + Hors ligne + Tomahawk::SpotifyParser @@ -2798,7 +2798,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. TomahawkApp - + My Collection Ma Collection @@ -3320,32 +3320,32 @@ saisissez le numéro PIN ici : Piste similaire - + Sorry, but we could not find similar tracks for this song! Désolé, on a pas pu trouver aucune pistes pour cette chanson! - + You've listened to this track %n time(s). Vous avez écouté cette piste %n fois.Vous avez écouté cette piste %n fois. - + You've never listened to this track before. Vous n'avez encore jamais écouté cette piste. - + You first listened to it on %1. Vous l'avez écouté pour la première fois le %1. - + You've listened to %1 %n time(s). Vous avez écouté %1 %n fois.Vous avez écouté %1 %n fois. - + You've never listened to %1 before. Vous n'avez encore jamais écouté %1. @@ -3536,12 +3536,12 @@ Vous pouvez envoyer un message de synchronisation quand vous le souhaitez en env Joués récemment - + No recently created playlists in your network. Pas de liste de lecture créée récemment sur votre réseau. - + Welcome to Tomahawk Bienvenue dans Tomahawk diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 146e38faf..85cdfaf0e 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -185,17 +185,17 @@ connect and stream from you? アルバム - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! プレイリストには何も入っていません。トラックを追加して、音楽を楽しみましょう! @@ -843,74 +843,74 @@ connect and stream from you? QObject - + %n year(s) ago one: %n年前 other: %n年前 - + %n year(s) one: %n年 other: %n年 - + %n month(s) ago one: %nヶ月前 other: %nヶ月前 - + %n month(s) one: %nヶ月 other: %nヶ月 - + %n week(s) ago one: %n週間前 other: %n週間前 - + %n week(s) one: %n週間 other: %n週間 - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1分前 - + %1 minutes %1分 - + just now 只今 @@ -1135,30 +1135,20 @@ other: %n週間 Top 10 - - - Offline - オフライン - All available tracks - - Online - オンライン - - - - + + Show - - + + Hide @@ -1205,7 +1195,7 @@ other: %n週間 - + Latest Additions @@ -1220,47 +1210,47 @@ other: %n週間 - + SuperCollection スーパーコレクション - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2690,37 +2680,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2744,36 +2734,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning 走査中 - + Checking - + Fetching 取得中 - + Parsing 解析中 - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2794,7 +2794,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -3315,32 +3315,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3526,12 +3526,12 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. - + Welcome to Tomahawk diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 07fd1a62a..9a49b147b 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -185,17 +185,17 @@ connect and stream from you? Albumy - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Ta lista jest aktualnie pusta. Dodaj do niej trochę piosenek i ciesz się muzyką! @@ -842,67 +842,67 @@ connect and stream from you? QObject - + %n year(s) ago %n rok temu%n lata temu%n lat temu - + %n year(s) %n rok%n lata%n lat - + %n month(s) ago %n miesiąc temu%n miesiące temu%n miesięcy temu - + %n month(s) %n miesiąc%n miesiące%n miesięcy - + %n week(s) ago %n tydzień temu%n tygodnie temu%n tygodni temu - + %n week(s) %n tydzień%n tygodnie%n tygodni - + %n day(s) ago %n dzień temu%n dni temu%n dni temu - + %n day(s) %n dzień%n dni%n dni - + %n hour(s) ago %n godzinę temu%n godziny temu%n godzin temu - + %n hour(s) %n godzinę%n godziny%n godzin - + %1 minutes ago %1 minut temu - + %1 minutes %1 minut - + just now przed chwilą @@ -1127,30 +1127,20 @@ connect and stream from you? Top 10 Top 10 - - - Offline - Offline - All available tracks Wszystkie dostępne utwory - - Online - Online - - - - + + Show Pokaż - - + + Hide Ukryj @@ -1197,7 +1187,7 @@ connect and stream from you? - + Latest Additions Ostatnio Dodane @@ -1212,47 +1202,47 @@ connect and stream from you? Ulubione Utwory - + SuperCollection Superkolekcja - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2688,37 +2678,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and i - + You Ty - + you ty - + and i - + %n other(s) %n inny%n inne%n innych - + %1 people - + loved this track @@ -2742,36 +2732,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Skanowanie (%L1 utworów) - + Scanning Skanowanie - + Checking Sprawdzanie - + Fetching Pobieranie - + Parsing Analizowanie - + Saving (%1%) Zapisywanie (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2792,7 +2792,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja @@ -3314,32 +3314,32 @@ wprowadź pokazany numer PIN tutaj: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3530,12 +3530,12 @@ Zawsze możesz ponownie wysłać wiadomość synchronizacyjną - po prostu wyśl Ostatnio Odtworzone Utwory - + No recently created playlists in your network. Brak ostatnio utworzonych list w twojej sieci. - + Welcome to Tomahawk Witaj w Tomahawk diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 08638cdd5..4b741a490 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -185,17 +185,17 @@ connect and stream from you? Álbuns - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Esta lista de reprodução está vazia. Adicione algumas faixas para disfrutar de uma música! @@ -842,67 +842,67 @@ connect and stream from you? QObject - + %n year(s) ago %n year ago%n years ago - + %n year(s) %n year%n years - + %n month(s) ago %n month ago%n months ago - + %n month(s) %n month%n months - + %n week(s) ago %n week ago%n weeks ago - + %n week(s) %n week%n weeks - + %n day(s) ago %n day ago%n days ago - + %n day(s) %n day%n days - + %n hour(s) ago %n hour ago%n hours ago - + %n hour(s) %n hour%n hours - + %1 minutes ago %1 minutos atrás - + %1 minutes %1 minutos - + just now agora @@ -1127,30 +1127,20 @@ connect and stream from you? Top 10 10 Mais - - - Offline - Desconectado - All available tracks Todas as faixas disponíveis - - Online - Conectado - - - - + + Show Mostrar - - + + Hide Ocultar @@ -1197,7 +1187,7 @@ connect and stream from you? - + Latest Additions @@ -1212,47 +1202,47 @@ connect and stream from you? Faixas favoritas - + SuperCollection - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2687,37 +2677,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and e - + You - + you - + and e - + %n other(s) - + %1 people %1 pessoas - + loved this track @@ -2741,36 +2731,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 faixas) - + Scanning Escaneando - + Checking Verificando - + Fetching Buscando - + Parsing Analisando - + Saving (%1%) Guardando (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2791,7 +2791,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca @@ -3313,32 +3313,32 @@ colocar o número PIN mostrado aqui: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3529,12 +3529,12 @@ Você pode enviar uma outra mensagem de sincronia a qualquer momento simplesment Faixas reproduzidas recentemente - + No recently created playlists in your network. Nenhuma lista de reprodução criada recentemente na sua rede. - + Welcome to Tomahawk Bem-vindo ao Tomahawk diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 2dfec0f95..c139bfcbe 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -186,17 +186,17 @@ connect and stream from you? Альбомы - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -771,12 +771,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Этот плейлист пустой. Добавьте какие-нибудь треки и наслаждайтесь музыкой! @@ -844,67 +844,67 @@ connect and stream from you? QObject - + %n year(s) ago %n год назад%n года назад%n лет назад - + %n year(s) %n год%n года%n лет - + %n month(s) ago %n месяц назад%n месяца назад%n месяцей назад - + %n month(s) %n месяц%n месяца%n месяцей - + %n week(s) ago %n неделю назад%n недели назад%n недель назад - + %n week(s) %n неделю%n недели%n недель - + %n day(s) ago %n день назад%n дня назад%n дней назад - + %n day(s) %n день%n дня%n дней - + %n hour(s) ago %n час назад%n часа назад%n часов назад - + %n hour(s) %n час%n часа%n часов - + %1 minutes ago %1 минут(ы) назад - + %1 minutes %1 минут(ы) - + just now только что @@ -1129,30 +1129,20 @@ connect and stream from you? Top 10 Топ 10 - - - Offline - Не в сети - All available tracks Доступные песни - - Online - В сети - - - - + + Show Показать - - + + Hide Спрятать @@ -1199,7 +1189,7 @@ connect and stream from you? - + Latest Additions Последние добавленные @@ -1214,47 +1204,47 @@ connect and stream from you? Любимые песни - + SuperCollection Общая коллекция - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2689,37 +2679,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and и - + You Ты - + you ты - + and и - + %n other(s) - + %1 people %1 человек - + loved this track любимый @@ -2743,36 +2733,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканирование (%L1 песни) - + Scanning Сканирую - + Checking Проверяю - + Fetching Выбираю - + Parsing Анализирую - + Saving (%1%) Сохраняю (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2793,7 +2793,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция @@ -3314,32 +3314,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3529,12 +3529,12 @@ You can re-send a sync message at any time simply by sending another tweet using Последние Воспроизводимые Песни - + No recently created playlists in your network. Нет списков, созданных в последнее время в вашей сети. - + Welcome to Tomahawk Добро пожаловать в Tomahawk diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 7792db58b..0d5e4907a 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -185,17 +185,17 @@ connect and stream from you? Album - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! Denna spellista är för närvarande tom. Lägg till några spår och njut av musiken! @@ -843,67 +843,67 @@ connect and stream from you? QObject - + %n year(s) ago %n år sedan%n år sedan - + %n year(s) %n år sedan%n år sedan - + %n month(s) ago %n månad sedan%n månader sedan - + %n month(s) %n månad%n månader - + %n week(s) ago %n vecka sedan%n veckor sedan - + %n week(s) %n vecka%n veckor - + %n day(s) ago %n dag sedan%n dagar sedan - + %n day(s) %n dag%n dagar - + %n hour(s) ago %n timme sedan%n timmar sedan - + %n hour(s) %n timme%n timmar - + %1 minutes ago %1 minuter sedan - + %1 minutes %1 minuter - + just now precis nyss @@ -1128,30 +1128,20 @@ connect and stream from you? Top 10 Topp 10 - - - Offline - Frånkopplad - All available tracks Alla tillgängliga spår - - Online - Ansluten - - - - + + Show Visa - - + + Hide Göm @@ -1198,7 +1188,7 @@ connect and stream from you? - + Latest Additions Senast tillagda @@ -1213,47 +1203,47 @@ connect and stream from you? Älskade låtar - + SuperCollection SuperCollection - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2683,37 +2673,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2737,36 +2727,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Söker igenom (%L1 spår) - + Scanning - + Checking Kontrollerar - + Fetching Hämtar - + Parsing Tolkar - + Saving (%1%) Sparar (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2787,7 +2787,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -3308,32 +3308,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3519,12 +3519,12 @@ You can re-send a sync message at any time simply by sending another tweet using Senaste spelade spår - + No recently created playlists in your network. Inga skapade spellistor i ditt nätverk på sistone. - + Welcome to Tomahawk Välkommen till Tomahawk diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index bf2ef0982..7c10de425 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -185,17 +185,17 @@ connect and stream from you? Albümler - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -842,67 +842,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -1127,30 +1127,20 @@ connect and stream from you? Top 10 - - - Offline - - All available tracks - - Online - - - - - + + Show - - + + Hide @@ -1197,7 +1187,7 @@ connect and stream from you? - + Latest Additions @@ -1212,47 +1202,47 @@ connect and stream from you? - + SuperCollection - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2682,37 +2672,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2736,36 +2726,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2786,7 +2786,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -3307,32 +3307,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3518,12 +3518,12 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. - + Welcome to Tomahawk diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index f1a31bb71..ff0048d67 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -185,17 +185,17 @@ connect and stream from you? 专辑 - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -842,67 +842,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago - + %1 minutes - + just now @@ -1127,30 +1127,20 @@ connect and stream from you? Top 10 - - - Offline - - All available tracks - - Online - - - - - + + Show - - + + Hide @@ -1197,7 +1187,7 @@ connect and stream from you? - + Latest Additions @@ -1212,47 +1202,47 @@ connect and stream from you? - + SuperCollection - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2682,37 +2672,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2736,36 +2726,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2786,7 +2786,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection @@ -3307,32 +3307,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3518,12 +3518,12 @@ You can re-send a sync message at any time simply by sending another tweet using - + No recently created playlists in your network. - + Welcome to Tomahawk diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index e15854c15..7cf9618c0 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -185,17 +185,17 @@ connect and stream from you? 專輯 - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -770,12 +770,12 @@ connect and stream from you? PlaylistView - + This playlist is currently empty. - + This playlist is currently empty. Add some tracks to it and enjoy the music! 目前這個播放清單是空的。請加入一些曲目,然後盡情享受音樂! @@ -842,67 +842,67 @@ connect and stream from you? QObject - + %n year(s) ago - + %n year(s) - + %n month(s) ago - + %n month(s) - + %n week(s) ago - + %n week(s) - + %n day(s) ago - + %n day(s) - + %n hour(s) ago - + %n hour(s) - + %1 minutes ago %1 分鐘前 - + %1 minutes %1 分鐘 - + just now 剛才 @@ -1127,30 +1127,20 @@ connect and stream from you? Top 10 前10名 - - - Offline - 離線 - All available tracks - - Online - 線上 - - - - + + Show 顯示 - - + + Hide 隱藏 @@ -1197,7 +1187,7 @@ connect and stream from you? - + Latest Additions 最新加入 @@ -1212,47 +1202,47 @@ connect and stream from you? - + SuperCollection 超級收藏 - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -2682,37 +2672,37 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Query - + and - + You - + you - + and - + %n other(s) - + %1 people - + loved this track @@ -2736,36 +2726,46 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing 解析 - + Saving (%1%) + + + Online + + + + + Offline + + Tomahawk::SpotifyParser @@ -2786,7 +2786,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection 我的收藏 @@ -3307,32 +3307,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. @@ -3518,12 +3518,12 @@ You can re-send a sync message at any time simply by sending another tweet using 最近播放的曲目 - + No recently created playlists in your network. 沒有最近建立的播放清單在您的網路。 - + Welcome to Tomahawk 歡迎到 Tomahawk From e36ea3b2633c0f209dd027703bc7563b6748046e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 09:14:49 +0200 Subject: [PATCH 321/433] Don't use auto-release pool and manually release created NSString* --- src/libtomahawk/mac/FileHelpers.mm | 7 ++++--- src/libtomahawk/utils/TomahawkUtils_Mac.mm | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/mac/FileHelpers.mm b/src/libtomahawk/mac/FileHelpers.mm index 6757d4786..3e3c01d27 100644 --- a/src/libtomahawk/mac/FileHelpers.mm +++ b/src/libtomahawk/mac/FileHelpers.mm @@ -85,9 +85,7 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza + (void)performMoveWithInfo:(NSDictionary *)info { - // *** GETS CALLED ON NON-MAIN THREAD! - - CAutoreleasePool _p; + // *** GETS CALLED ON NON-MAIN THREAD! NSString* fromPath = [info objectForKey: TKCopySourceKey]; NSString* toPath = [info objectForKey: TKCopyDestinationKey]; @@ -204,6 +202,9 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]; [self notifyDelegate:dict]; + + [fromPath release]; + [toPath release]; } diff --git a/src/libtomahawk/utils/TomahawkUtils_Mac.mm b/src/libtomahawk/utils/TomahawkUtils_Mac.mm index fa82f9d76..28b03e0e3 100644 --- a/src/libtomahawk/utils/TomahawkUtils_Mac.mm +++ b/src/libtomahawk/utils/TomahawkUtils_Mac.mm @@ -61,6 +61,8 @@ if ( receiver ) QMetaObject::invokeMethod(receiver, "installSucceeded", Qt::DirectConnection, Q_ARG(QString, path)); + [target release]; + } - (void)moveFailedWithError:(NSError *)error From 69ed522954185a4c80edb762d9f3e2a8b9bd5fea Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 09:15:15 +0200 Subject: [PATCH 322/433] TWK-922: Text fix for Account delegate --- src/libtomahawk/accounts/AccountDelegate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/AccountDelegate.cpp b/src/libtomahawk/accounts/AccountDelegate.cpp index a674d582b..8b77aabca 100644 --- a/src/libtomahawk/accounts/AccountDelegate.cpp +++ b/src/libtomahawk/accounts/AccountDelegate.cpp @@ -270,7 +270,7 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, } else if ( canDelete ) { - const QString btnText = tr( "Remove Account" ); + const QString btnText = tr( "Remove" ); const int btnWidth = installMetrics.width( btnText ) + 2*PADDING; QRect btnRect; From 224b46f5b076823cc19b9a38c0d93b6dad0e97bb Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 09:24:19 +0200 Subject: [PATCH 323/433] Only wait for shutdown of script resolver if it's running --- src/libtomahawk/resolvers/ScriptResolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 2392c5893..3b7c58276 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -69,7 +69,7 @@ ScriptResolver::~ScriptResolver() msg[ "_msgtype" ] = "quit"; sendMessage( msg ); - bool finished = m_proc.waitForFinished( 2500 ); // might call handleMsg + bool finished = m_proc.state() != QProcess::Running || m_proc.waitForFinished( 2500 ); // might call handleMsg Tomahawk::Pipeline::instance()->removeResolver( this ); From 59ab945f0b46f5d624d76fb86f806871b4e33454 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 14:19:08 +0200 Subject: [PATCH 324/433] Fix stupid regression in sizegrip hiding when fullscreening --- src/mac/TomahawkApp_Mac.mm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mac/TomahawkApp_Mac.mm b/src/mac/TomahawkApp_Mac.mm index 187981dcf..c9ab976a6 100644 --- a/src/mac/TomahawkApp_Mac.mm +++ b/src/mac/TomahawkApp_Mac.mm @@ -253,10 +253,12 @@ void Tomahawk::checkForUpdates() { #ifdef LION #define SET_LION_FULLSCREEN NSWindowCollectionBehaviorFullScreenPrimary -#define LION_FULLSCREEN_NOTIFICATION_VALUE NSWindowWillEnterFullScreenNotification +#define LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE NSWindowWillEnterFullScreenNotification +#define LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE NSWindowDidExitFullScreenNotification #else #define SET_LION_FULLSCREEN (NSUInteger)(1 << 7) // Defined as NSWindowCollectionBehaviorFullScreenPrimary in lion's NSWindow.h -#define LION_FULLSCREEN_NOTIFICATION_VALUE @"NSWindowWillEnterFullScreenNotification" +#define LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE @"NSWindowWillEnterFullScreenNotification" +#define LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE @"NSWindowDidExitFullScreenNotification" #endif void Tomahawk::enableFullscreen( QObject* receiver ) @@ -281,14 +283,14 @@ void Tomahawk::enableFullscreen( QObject* receiver ) if ( !receiver ) continue; - [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_NOTIFICATION_VALUE + [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_ENTER_NOTIFICATION_VALUE object:nswindow queue:nil usingBlock:^(NSNotification * note) { NSLog(@"Became Full Screen!"); QMetaObject::invokeMethod( receiver, "fullScreenEntered", Qt::DirectConnection ); }]; - [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_NOTIFICATION_VALUE + [[NSNotificationCenter defaultCenter] addObserverForName:LION_FULLSCREEN_EXIT_NOTIFICATION_VALUE object:nswindow queue:nil usingBlock:^(NSNotification * note) { From e0d6d5ef6badbf3cfa5318a2c6a6a650666ebac0 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 15:32:08 +0200 Subject: [PATCH 325/433] Move spotify account to libtomahawk --- src/CMakeLists.txt | 5 ----- src/libtomahawk/CMakeLists.txt | 6 ++++++ src/{ => libtomahawk}/accounts/spotify/SpotifyAccount.cpp | 0 src/{ => libtomahawk}/accounts/spotify/SpotifyAccount.h | 7 ++++--- .../accounts/spotify/SpotifyAccountConfig.cpp | 0 .../accounts/spotify/SpotifyAccountConfig.h | 0 .../accounts/spotify/SpotifyAccountConfig.ui | 0 .../accounts/spotify/SpotifyPlaylistUpdater.cpp | 0 .../accounts/spotify/SpotifyPlaylistUpdater.h | 5 +++-- 9 files changed, 13 insertions(+), 10 deletions(-) rename src/{ => libtomahawk}/accounts/spotify/SpotifyAccount.cpp (100%) rename src/{ => libtomahawk}/accounts/spotify/SpotifyAccount.h (96%) rename src/{ => libtomahawk}/accounts/spotify/SpotifyAccountConfig.cpp (100%) rename src/{ => libtomahawk}/accounts/spotify/SpotifyAccountConfig.h (100%) rename src/{ => libtomahawk}/accounts/spotify/SpotifyAccountConfig.ui (100%) rename src/{ => libtomahawk}/accounts/spotify/SpotifyPlaylistUpdater.cpp (100%) rename src/{ => libtomahawk}/accounts/spotify/SpotifyPlaylistUpdater.h (95%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61479c7c7..fba02bab7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,10 +72,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} accounts/lastfm/LastFmConfig.cpp accounts/lastfm/LastFmInfoPlugin.cpp - accounts/spotify/SpotifyAccount.cpp - accounts/spotify/SpotifyAccountConfig.cpp - accounts/spotify/SpotifyPlaylistUpdater.cpp - TomahawkTrayIcon.cpp AudioControls.cpp SettingsDialog.cpp @@ -97,7 +93,6 @@ SET( tomahawkUI ${tomahawkUI} ProxyDialog.ui accounts/lastfm/LastFmConfig.ui - accounts/spotify/SpotifyAccountConfig.ui AudioControls.ui LoadXSPFDialog.ui diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 501d84cc6..cdf5ebd32 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -184,6 +184,11 @@ set( libSources accounts/DelegateConfigWrapper.cpp accounts/AccountFactoryWrapper.cpp accounts/AccountFactoryWrapperDelegate.cpp + + accounts/spotify/SpotifyAccount.cpp + accounts/spotify/SpotifyAccountConfig.cpp + accounts/spotify/SpotifyPlaylistUpdater.cpp + sip/SipPlugin.cpp sip/SipHandler.cpp sip/SipInfo.cpp @@ -306,6 +311,7 @@ set( libUI ${libUI} context/ContextWidget.ui infobar/InfoBar.ui accounts/AccountFactoryWrapper.ui + accounts/spotify/SpotifyAccountConfig.ui ) include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. .. diff --git a/src/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp similarity index 100% rename from src/accounts/spotify/SpotifyAccount.cpp rename to src/libtomahawk/accounts/spotify/SpotifyAccount.cpp diff --git a/src/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h similarity index 96% rename from src/accounts/spotify/SpotifyAccount.h rename to src/libtomahawk/accounts/spotify/SpotifyAccount.h index 69448b27b..f31d97309 100644 --- a/src/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -26,6 +26,7 @@ #include "Playlist.h" #include "utils/TomahawkUtils.h" #include "utils/SmartPointerList.h" +#include "DllMacro.h" class QAction; class SpotifyPlaylistUpdater; @@ -51,7 +52,7 @@ struct SpotifyPlaylistInfo { }; -class SpotifyAccountFactory : public AccountFactory +class DLLEXPORT SpotifyAccountFactory : public AccountFactory { Q_OBJECT public: @@ -69,7 +70,7 @@ public: }; -class SpotifyAccount : public CustomAtticaAccount +class DLLEXPORT SpotifyAccount : public CustomAtticaAccount { Q_OBJECT public: @@ -159,6 +160,6 @@ private: } } -Q_DECLARE_METATYPE( Tomahawk::Accounts::SpotifyPlaylistInfo* ); +Q_DECLARE_METATYPE( Tomahawk::Accounts::SpotifyPlaylistInfo* ) #endif // SpotifyAccount_H diff --git a/src/accounts/spotify/SpotifyAccountConfig.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp similarity index 100% rename from src/accounts/spotify/SpotifyAccountConfig.cpp rename to src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp diff --git a/src/accounts/spotify/SpotifyAccountConfig.h b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h similarity index 100% rename from src/accounts/spotify/SpotifyAccountConfig.h rename to src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h diff --git a/src/accounts/spotify/SpotifyAccountConfig.ui b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.ui similarity index 100% rename from src/accounts/spotify/SpotifyAccountConfig.ui rename to src/libtomahawk/accounts/spotify/SpotifyAccountConfig.ui diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.cpp b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp similarity index 100% rename from src/accounts/spotify/SpotifyPlaylistUpdater.cpp rename to src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.h b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h similarity index 95% rename from src/accounts/spotify/SpotifyPlaylistUpdater.h rename to src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h index d07fc172a..896e507d3 100644 --- a/src/accounts/spotify/SpotifyPlaylistUpdater.h +++ b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h @@ -21,6 +21,7 @@ #include "playlist/PlaylistUpdaterInterface.h" #include "utils/Closure.h" +#include "DllMacro.h" #include #include @@ -31,7 +32,7 @@ namespace Accounts { } } -class SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface +class DLLEXPORT SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface { Q_OBJECT @@ -106,7 +107,7 @@ private: }; -class SpotifyUpdaterFactory : public Tomahawk::PlaylistUpdaterFactory +class DLLEXPORT SpotifyUpdaterFactory : public Tomahawk::PlaylistUpdaterFactory { public: SpotifyUpdaterFactory() {} From 7af7a8784f85205e4a3434a4a175e5c3a91b3d20 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 15:43:06 +0200 Subject: [PATCH 326/433] Remove assert as it might happen in valid conditions sometimes --- src/libtomahawk/accounts/spotify/SpotifyAccount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index 5f4add6ec..a7b87d896 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -822,7 +822,7 @@ SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVa */ if ( m_updaters.contains( id ) ) { - Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before + //Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before m_updaters[ id ]->setSync( true ); // m_updaters[ id ]-> // TODO From c9edf98dd2058044e1ff00cb3a7073669e860332 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 15:44:36 +0200 Subject: [PATCH 327/433] Better reasoning in comments --- src/libtomahawk/accounts/spotify/SpotifyAccount.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index a7b87d896..d786be550 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -822,7 +822,8 @@ SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVa */ if ( m_updaters.contains( id ) ) { - //Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before + //Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before, but might not be if the user + // changed spotify resolver meanwhile, so allow it for now m_updaters[ id ]->setSync( true ); // m_updaters[ id ]-> // TODO From ce19d8c70b7709a2ac7949dcd7c64275e8d5aa9a Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 15:59:23 +0200 Subject: [PATCH 328/433] Move Last.fm account to libtomahawk --- src/CMakeLists.txt | 6 ------ src/libtomahawk/CMakeLists.txt | 5 +++++ src/{ => libtomahawk}/accounts/lastfm/LastFmAccount.cpp | 0 src/{ => libtomahawk}/accounts/lastfm/LastFmAccount.h | 7 ++++--- src/{ => libtomahawk}/accounts/lastfm/LastFmConfig.cpp | 0 src/{ => libtomahawk}/accounts/lastfm/LastFmConfig.h | 0 src/{ => libtomahawk}/accounts/lastfm/LastFmConfig.ui | 0 src/{ => libtomahawk}/accounts/lastfm/LastFmInfoPlugin.cpp | 0 src/{ => libtomahawk}/accounts/lastfm/LastFmInfoPlugin.h | 3 ++- 9 files changed, 11 insertions(+), 10 deletions(-) rename src/{ => libtomahawk}/accounts/lastfm/LastFmAccount.cpp (100%) rename src/{ => libtomahawk}/accounts/lastfm/LastFmAccount.h (92%) rename src/{ => libtomahawk}/accounts/lastfm/LastFmConfig.cpp (100%) rename src/{ => libtomahawk}/accounts/lastfm/LastFmConfig.h (100%) rename src/{ => libtomahawk}/accounts/lastfm/LastFmConfig.ui (100%) rename src/{ => libtomahawk}/accounts/lastfm/LastFmInfoPlugin.cpp (100%) rename src/{ => libtomahawk}/accounts/lastfm/LastFmInfoPlugin.h (97%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fba02bab7..f283094f5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,10 +68,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/items/GroupItem.cpp sourcetree/items/HistoryItem.cpp - accounts/lastfm/LastFmAccount.cpp - accounts/lastfm/LastFmConfig.cpp - accounts/lastfm/LastFmInfoPlugin.cpp - TomahawkTrayIcon.cpp AudioControls.cpp SettingsDialog.cpp @@ -92,8 +88,6 @@ SET( tomahawkUI ${tomahawkUI} StackedSettingsDialog.ui ProxyDialog.ui - accounts/lastfm/LastFmConfig.ui - AudioControls.ui LoadXSPFDialog.ui SocialWidget.ui diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index cdf5ebd32..d3b4c8ed3 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -189,6 +189,10 @@ set( libSources accounts/spotify/SpotifyAccountConfig.cpp accounts/spotify/SpotifyPlaylistUpdater.cpp + accounts/lastfm/LastFmAccount.cpp + accounts/lastfm/LastFmConfig.cpp + accounts/lastfm/LastFmInfoPlugin.cpp + sip/SipPlugin.cpp sip/SipHandler.cpp sip/SipInfo.cpp @@ -312,6 +316,7 @@ set( libUI ${libUI} infobar/InfoBar.ui accounts/AccountFactoryWrapper.ui accounts/spotify/SpotifyAccountConfig.ui + accounts/lastfm/LastFmConfig.ui ) include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. .. diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/libtomahawk/accounts/lastfm/LastFmAccount.cpp similarity index 100% rename from src/accounts/lastfm/LastFmAccount.cpp rename to src/libtomahawk/accounts/lastfm/LastFmAccount.cpp diff --git a/src/accounts/lastfm/LastFmAccount.h b/src/libtomahawk/accounts/lastfm/LastFmAccount.h similarity index 92% rename from src/accounts/lastfm/LastFmAccount.h rename to src/libtomahawk/accounts/lastfm/LastFmAccount.h index 90ca37737..f1b7ffc0c 100644 --- a/src/accounts/lastfm/LastFmAccount.h +++ b/src/libtomahawk/accounts/lastfm/LastFmAccount.h @@ -21,6 +21,7 @@ #include "accounts/Account.h" #include "AtticaManager.h" +#include "DllMacro.h" #include @@ -37,7 +38,7 @@ namespace Accounts { class LastFmConfig; -class LastFmAccountFactory : public AccountFactory +class DLLEXPORT LastFmAccountFactory : public AccountFactory { Q_OBJECT public: @@ -57,11 +58,11 @@ private: }; /** - * 3.Last.Fm account is special. It is both an attica resolver *and* a InfoPlugin. We always want the infoplugin, + * Last.Fm account is special. It is both an attica resolver *and* a InfoPlugin. We always want the infoplugin, * but the user can install the attica resolver on-demand. So we take care of both there. * */ -class LastFmAccount : public CustomAtticaAccount +class DLLEXPORT LastFmAccount : public CustomAtticaAccount { Q_OBJECT public: diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp similarity index 100% rename from src/accounts/lastfm/LastFmConfig.cpp rename to src/libtomahawk/accounts/lastfm/LastFmConfig.cpp diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/libtomahawk/accounts/lastfm/LastFmConfig.h similarity index 100% rename from src/accounts/lastfm/LastFmConfig.h rename to src/libtomahawk/accounts/lastfm/LastFmConfig.h diff --git a/src/accounts/lastfm/LastFmConfig.ui b/src/libtomahawk/accounts/lastfm/LastFmConfig.ui similarity index 100% rename from src/accounts/lastfm/LastFmConfig.ui rename to src/libtomahawk/accounts/lastfm/LastFmConfig.ui diff --git a/src/accounts/lastfm/LastFmInfoPlugin.cpp b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp similarity index 100% rename from src/accounts/lastfm/LastFmInfoPlugin.cpp rename to src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp diff --git a/src/accounts/lastfm/LastFmInfoPlugin.h b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h similarity index 97% rename from src/accounts/lastfm/LastFmInfoPlugin.h rename to src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h index 0e5024fee..f744c740e 100644 --- a/src/accounts/lastfm/LastFmInfoPlugin.h +++ b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h @@ -22,6 +22,7 @@ #include "infosystem/InfoSystem.h" #include "infosystem/InfoSystemWorker.h" +#include "DllMacro.h" #include #include @@ -42,7 +43,7 @@ namespace Accounts namespace InfoSystem { -class LastFmInfoPlugin : public InfoPlugin +class DLLEXPORT LastFmInfoPlugin : public InfoPlugin { Q_OBJECT From 53dd69e2f31e2bcdddd91b17b4a9b0a1d729b981 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 16:37:33 +0200 Subject: [PATCH 329/433] TWK-736: Tooltip for currently playing song for peers --- src/sourcetree/SourcesModel.cpp | 27 +++++++++++++++++---------- src/sourcetree/items/SourceItem.cpp | 10 ++++++++++ src/sourcetree/items/SourceItem.h | 1 + src/sourcetree/items/SourceTreeItem.h | 1 + 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/sourcetree/SourcesModel.cpp b/src/sourcetree/SourcesModel.cpp index 2c383ef40..1b532e3b8 100644 --- a/src/sourcetree/SourcesModel.cpp +++ b/src/sourcetree/SourcesModel.cpp @@ -101,41 +101,48 @@ SourcesModel::data( const QModelIndex& index, int role ) const if ( !index.isValid() ) return QVariant(); + SourceTreeItem* item = itemFromIndex( index ); + if ( !item ) + return QVariant(); + switch ( role ) { case Qt::SizeHintRole: return QSize( 0, 18 ); case SourceTreeItemRole: - return QVariant::fromValue< SourceTreeItem* >( itemFromIndex( index ) ); + return QVariant::fromValue< SourceTreeItem* >( item ); case SourceTreeItemTypeRole: - return itemFromIndex( index )->type(); + return item->type(); case Qt::DisplayRole: case Qt::EditRole: - return itemFromIndex( index )->text(); + return item->text(); case Qt::DecorationRole: - return itemFromIndex( index )->icon(); + return item->icon(); case SourcesModel::SortRole: - return itemFromIndex( index )->peerSortValue(); + return item->peerSortValue(); case SourcesModel::IDRole: - return itemFromIndex( index )->IDValue(); + return item->IDValue(); case SourcesModel::LatchedOnRole: { - if ( itemFromIndex( index )->type() == Collection ) + if ( item->type() == Collection ) { - SourceItem* cItem = qobject_cast< SourceItem* >( itemFromIndex( index ) ); + SourceItem* cItem = qobject_cast< SourceItem* >( item ); return cItem->localLatchedOn(); } return false; } case SourcesModel::LatchedRealtimeRole: { - if ( itemFromIndex( index )->type() == Collection ) + if ( item->type() == Collection ) { - SourceItem* cItem = qobject_cast< SourceItem* >( itemFromIndex( index ) ); + SourceItem* cItem = qobject_cast< SourceItem* >( item ); return cItem->localLatchMode() == Tomahawk::PlaylistModes::RealTime; } return false; } + case Qt::ToolTipRole: + if ( !item->tooltip().isEmpty() ) + return item->tooltip(); } return QVariant(); } diff --git a/src/sourcetree/items/SourceItem.cpp b/src/sourcetree/items/SourceItem.cpp index 03f7be0db..4847d8512 100644 --- a/src/sourcetree/items/SourceItem.cpp +++ b/src/sourcetree/items/SourceItem.cpp @@ -145,6 +145,16 @@ SourceItem::text() const } +QString +SourceItem::tooltip() const +{ + if ( !m_source.isNull() && !m_source->currentTrack().isNull() ) + return m_source->textStatus(); + + return QString(); +} + + int SourceItem::IDValue() const { diff --git a/src/sourcetree/items/SourceItem.h b/src/sourcetree/items/SourceItem.h index 7f4a87ed8..cd6711735 100644 --- a/src/sourcetree/items/SourceItem.h +++ b/src/sourcetree/items/SourceItem.h @@ -38,6 +38,7 @@ public: SourceItem( SourcesModel* model, SourceTreeItem* parent, const Tomahawk::source_ptr& source ); virtual QString text() const; + virtual QString tooltip() const; virtual QIcon icon() const; virtual int peerSortValue() const; virtual int IDValue() const; diff --git a/src/sourcetree/items/SourceTreeItem.h b/src/sourcetree/items/SourceTreeItem.h index b2a527a05..410542e9e 100644 --- a/src/sourcetree/items/SourceTreeItem.h +++ b/src/sourcetree/items/SourceTreeItem.h @@ -58,6 +58,7 @@ public: // varies depending on the type of the item virtual QString text() const { return QString(); } + virtual QString tooltip() const { return QString(); } virtual Qt::ItemFlags flags() const { return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } virtual QIcon icon() const { return QIcon(); } virtual bool willAcceptDrag( const QMimeData* ) const { return false; } From 13945286ac85ff4c30eb1f5d5f5916d8f861f865 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:00:41 +0200 Subject: [PATCH 330/433] * Fixed ACLRegistry for headless. --- src/libtomahawk/AclRegistry.cpp | 14 ++++++++++---- src/libtomahawk/AclRegistry.h | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/AclRegistry.cpp b/src/libtomahawk/AclRegistry.cpp index 5ae2262c9..56653187f 100644 --- a/src/libtomahawk/AclRegistry.cpp +++ b/src/libtomahawk/AclRegistry.cpp @@ -26,10 +26,13 @@ #include "TomahawkApp.h" #include "Source.h" +#ifndef ENABLE_HEADLESS + #include "jobview/AclJobItem.h" + #include "jobview/JobStatusView.h" + #include "jobview/JobStatusModel.h" +#endif + #include "utils/Logger.h" -#include "jobview/AclJobItem.h" -#include "jobview/JobStatusView.h" -#include "jobview/JobStatusModel.h" ACLRegistry* ACLRegistry::s_instance = 0; @@ -124,6 +127,7 @@ ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACL return ACLRegistry::NotFound; } #endif + m_cache.append( user ); emit aclResult( dbid, username, user.acl ); return user.acl; @@ -131,6 +135,7 @@ ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACL #ifndef ENABLE_HEADLESS + void ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username ) { @@ -138,7 +143,6 @@ ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username ) m_jobQueue.enqueue( job ); queueNextJob(); } -#endif void @@ -189,6 +193,8 @@ ACLRegistry::queueNextJob() } } +#endif + void ACLRegistry::load() diff --git a/src/libtomahawk/AclRegistry.h b/src/libtomahawk/AclRegistry.h index 373d673a2..5405635c7 100644 --- a/src/libtomahawk/AclRegistry.h +++ b/src/libtomahawk/AclRegistry.h @@ -86,13 +86,13 @@ public slots: **/ ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false ); - #ifndef ENABLE_HEADLESS +#ifndef ENABLE_HEADLESS void getUserDecision( ACLRegistry::User user, const QString &username ); - #endif private slots: void userDecision( ACLRegistry::User user ); void queueNextJob(); +#endif private: /** From 1abe69079f583d93c17d354b9c799e4f5967bfd2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:01:03 +0200 Subject: [PATCH 331/433] * Fixed Query for headless. --- src/libtomahawk/Query.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index 4d803f776..32b2b77b5 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -776,7 +776,6 @@ Query::cover( const QSize& size, bool forceLoad ) const return QPixmap(); } -#endif bool @@ -791,6 +790,8 @@ Query::coverLoaded() const return m_artistPtr->coverLoaded(); } +#endif + QList Query::similarTracks() const From 973436a09b40ec06c5f2c44944b1081d33e3b482 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:01:23 +0200 Subject: [PATCH 332/433] * Fixed Source for headless. --- src/libtomahawk/Source.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/Source.cpp b/src/libtomahawk/Source.cpp index db331385f..1d781fb8f 100644 --- a/src/libtomahawk/Source.cpp +++ b/src/libtomahawk/Source.cpp @@ -34,11 +34,15 @@ #include #include -#include "utils/Logger.h" -#include "utils/TomahawkUtilsGui.h" #include "utils/TomahawkCache.h" #include "database/DatabaseCommand_SocialAction.h" +#ifndef ENABLE_HEADLESS + #include "utils/TomahawkUtilsGui.h" +#endif + +#include "utils/Logger.h" + using namespace Tomahawk; From 320182427f1c0425cb0b447a12758834c21f83f9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:02:17 +0200 Subject: [PATCH 333/433] * Fixed SipPlugin for headless. --- src/libtomahawk/sip/SipPlugin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libtomahawk/sip/SipPlugin.cpp b/src/libtomahawk/sip/SipPlugin.cpp index 694bf03e0..ad1d296fa 100644 --- a/src/libtomahawk/sip/SipPlugin.cpp +++ b/src/libtomahawk/sip/SipPlugin.cpp @@ -58,12 +58,16 @@ SipPlugin::serviceName() const } +#ifndef ENABLE_HEADLESS + QMenu* SipPlugin::menu() { return 0; } +#endif + Tomahawk::Accounts::Account* SipPlugin::account() const From eecf2c38d2e2311e91d05a6bc68178d8ada69409 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:03:12 +0200 Subject: [PATCH 334/433] * Fixed ShortenedLinkParser for headless. --- src/libtomahawk/utils/ShortenedLinkParser.cpp | 8 +++++++- src/libtomahawk/utils/ShortenedLinkParser.h | 10 +++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/utils/ShortenedLinkParser.cpp b/src/libtomahawk/utils/ShortenedLinkParser.cpp index 6452e1b0c..f683795ac 100644 --- a/src/libtomahawk/utils/ShortenedLinkParser.cpp +++ b/src/libtomahawk/utils/ShortenedLinkParser.cpp @@ -69,8 +69,9 @@ ShortenedLinkParser::handlesUrl( const QString& url ) url.contains( "rd.io" ) ); } + void -ShortenedLinkParser::lookupUrl ( const QString& url ) +ShortenedLinkParser::lookupUrl( const QString& url ) { tDebug() << "Looking up..." << url; QString cleaned = url; @@ -87,6 +88,7 @@ ShortenedLinkParser::lookupUrl ( const QString& url ) } + void ShortenedLinkParser::lookupFinished() { @@ -128,6 +130,8 @@ ShortenedLinkParser::checkFinished() } +#ifndef ENABLE_HEADLESS + QPixmap ShortenedLinkParser::pixmap() { @@ -136,3 +140,5 @@ ShortenedLinkParser::pixmap() return *s_pixmap; } + +#endif diff --git a/src/libtomahawk/utils/ShortenedLinkParser.h b/src/libtomahawk/utils/ShortenedLinkParser.h index 53131f932..b50ce17ec 100644 --- a/src/libtomahawk/utils/ShortenedLinkParser.h +++ b/src/libtomahawk/utils/ShortenedLinkParser.h @@ -26,7 +26,10 @@ #include #include #include -#include + +#ifndef ENABLE_HEADLESS + #include +#endif class QNetworkReply; @@ -61,13 +64,14 @@ private: void lookupUrl( const QString& url ); void checkFinished(); +#ifndef ENABLE_HEADLESS static QPixmap pixmap(); + static QPixmap* s_pixmap; +#endif QStringList m_links; QSet< QNetworkReply* > m_queries; DropJobNotifier* m_expandJob; - - static QPixmap* s_pixmap; }; } From e9a1157e000ea3b14093800e1d7258735c38b35c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:04:45 +0200 Subject: [PATCH 335/433] * Fixed DbCmd_UpdateSearchIndex for headless. --- .../DatabaseCommand_UpdateSearchIndex.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp b/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp index e0bc3558a..5130d7c04 100644 --- a/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp +++ b/src/libtomahawk/database/DatabaseCommand_UpdateSearchIndex.cpp @@ -19,16 +19,20 @@ #include "DatabaseCommand_UpdateSearchIndex.h" -#include "DatabaseImpl.h" -#include "TomahawkSqlQuery.h" -#include "utils/Logger.h" -#include "jobview/IndexingJobItem.h" -#include "jobview/JobStatusView.h" -#include "jobview/JobStatusModel.h" -#include "Source.h" - #include +#include "DatabaseImpl.h" +#include "Source.h" +#include "TomahawkSqlQuery.h" +#include "jobview/IndexingJobItem.h" + +#ifndef ENABLE_HEADLESS + #include "jobview/JobStatusView.h" + #include "jobview/JobStatusModel.h" +#endif + +#include "utils/Logger.h" + DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex() : DatabaseCommand() @@ -36,14 +40,18 @@ DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex() { tLog() << Q_FUNC_INFO << "Updating index."; +#ifndef ENABLE_HEADLESS JobStatusView::instance()->model()->addJob( m_statusJob.data() ); +#endif } DatabaseCommand_UpdateSearchIndex::~DatabaseCommand_UpdateSearchIndex() { - if (! m_statusJob.isNull() ) +#ifndef ENABLE_HEADLESS + if ( ! m_statusJob.isNull() ) m_statusJob.data()->done(); +#endif } From b908854d5968b4b541e4ed1ba61ca4730b35cf03 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:05:41 +0200 Subject: [PATCH 336/433] * Fixed Account for headless. --- src/libtomahawk/accounts/Account.cpp | 5 +++++ src/libtomahawk/accounts/Account.h | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/accounts/Account.cpp b/src/libtomahawk/accounts/Account.cpp index 7ab25d226..e182889eb 100644 --- a/src/libtomahawk/accounts/Account.cpp +++ b/src/libtomahawk/accounts/Account.cpp @@ -64,6 +64,8 @@ Account::~Account() } +#ifndef ENABLE_HEADLESS + QWidget* Account::configurationWidget() { @@ -84,6 +86,9 @@ Account::icon() const return QPixmap(); } +#endif + + void Account::authenticate() { diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 6b8b35cb3..cb61cdf74 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -82,17 +82,18 @@ public: /** * Configuration widgets can have a "dataError( bool )" signal to enable/disable the OK button in their wrapper dialogs. */ +#ifndef ENABLE_HEADLESS virtual QWidget* configurationWidget() = 0; virtual QWidget* aboutWidget() { return 0; } + virtual QWidget* aclWidget() = 0; + virtual QPixmap icon() const = 0; +#endif virtual void saveConfig() {} // called when the widget has been edited. save values from config widget, call sync() to write to disk account generic settings QVariantHash credentials() const { QMutexLocker locker( &m_mutex ); return m_credentials; } QVariantMap acl() const { QMutexLocker locker( &m_mutex ); return m_acl; } - virtual QWidget* aclWidget() = 0; - - virtual QPixmap icon() const = 0; virtual ConnectionState connectionState() const = 0; virtual bool isAuthenticated() const = 0; From c02edee1000360240ca7149801f70dea33db7f20 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:06:23 +0200 Subject: [PATCH 337/433] * Fixed GlobalActionManager for headless. --- src/libtomahawk/GlobalActionManager.cpp | 54 +++++++++++++++++-------- src/libtomahawk/GlobalActionManager.h | 49 +++++++++++++--------- 2 files changed, 66 insertions(+), 37 deletions(-) diff --git a/src/libtomahawk/GlobalActionManager.cpp b/src/libtomahawk/GlobalActionManager.cpp index a35d4d77c..4fca818b1 100644 --- a/src/libtomahawk/GlobalActionManager.cpp +++ b/src/libtomahawk/GlobalActionManager.cpp @@ -41,13 +41,15 @@ #include "utils/ShortenedLinkParser.h" #include "utils/RdioParser.h" -#include "widgets/SearchWidget.h" -#include "ViewManager.h" -#include "playlist/topbar/TopBar.h" -#include "playlist/PlaylistView.h" +#ifndef ENABLE_HEADLESS + #include "ViewManager.h" + #include "playlist/topbar/TopBar.h" + #include "playlist/PlaylistView.h" + #include "widgets/SearchWidget.h" -#include -#include + #include + #include +#endif #include #include @@ -133,6 +135,8 @@ GlobalActionManager::shortenLink( const QUrl& url, const QVariant& callbackObj ) } +#ifndef ENABLE_HEADLESS + void GlobalActionManager::getShortLink( const playlist_ptr& pl ) { @@ -178,6 +182,7 @@ GlobalActionManager::getShortLink( const playlist_ptr& pl ) connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), SLOT( shortenLinkRequestError( QNetworkReply::NetworkError ) ) ); } + QString GlobalActionManager::copyPlaylistToClipboard( const dynplaylist_ptr& playlist ) { @@ -423,6 +428,7 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url ) return false; } + void GlobalActionManager::playlistCreatedToShow( const playlist_ptr& pl ) { @@ -430,7 +436,9 @@ GlobalActionManager::playlistCreatedToShow( const playlist_ptr& pl ) pl->setProperty( "sharedptr", QVariant::fromValue( pl ) ); } -void GlobalActionManager::playlistReadyToShow() + +void +GlobalActionManager::playlistReadyToShow() { playlist_ptr pl = sender()->property( "sharedptr" ).value(); if ( !pl.isNull() ) @@ -460,7 +468,7 @@ GlobalActionManager::handleCollectionCommand( const QUrl& url ) bool -GlobalActionManager::handleOpenCommand(const QUrl& url) +GlobalActionManager::handleOpenCommand( const QUrl& url ) { QStringList parts = url.path().split( "/" ).mid( 1 ); if ( parts.isEmpty() ) @@ -474,7 +482,7 @@ GlobalActionManager::handleOpenCommand(const QUrl& url) void -GlobalActionManager::handleOpenTrack ( const query_ptr& q ) +GlobalActionManager::handleOpenTrack( const query_ptr& q ) { ViewManager::instance()->queue()->model()->append( q ); ViewManager::instance()->showQueue(); @@ -486,6 +494,7 @@ GlobalActionManager::handleOpenTrack ( const query_ptr& q ) } } + void GlobalActionManager::handlePlayTrack( const query_ptr& qry ) { @@ -493,7 +502,6 @@ GlobalActionManager::handlePlayTrack( const query_ptr& qry ) } - bool GlobalActionManager::handleQueueCommand( const QUrl& url ) { @@ -996,6 +1004,8 @@ GlobalActionManager::playRdio( const QUrl& url ) return true; } +#endif + bool GlobalActionManager::handleBookmarkCommand(const QUrl& url) { @@ -1076,6 +1086,7 @@ GlobalActionManager::shortenLinkRequestFinished() if ( !shortUrl.isValid() ) error = true; +#ifndef ENABLE_HEADLESS // Success! Here is the short link if ( m_clipboardLongUrl == reply->request().url() ) { @@ -1088,6 +1099,7 @@ GlobalActionManager::shortenLinkRequestFinished() m_clipboardLongUrl.clear(); } else +#endif { if ( !error ) emit shortLinkReady( longUrl, shortUrl, callbackObj ); @@ -1099,6 +1111,8 @@ GlobalActionManager::shortenLinkRequestFinished() } +#ifndef ENABLE_HEADLESS + void GlobalActionManager::postShortenFinished() { @@ -1118,6 +1132,9 @@ GlobalActionManager::postShortenFinished() reply->deleteLater(); } +#endif + + void GlobalActionManager::shortenLinkRequestError( QNetworkReply::NetworkError error ) { @@ -1172,6 +1189,8 @@ GlobalActionManager::doBookmark( const playlist_ptr& pl, const query_ptr& q ) } +#ifndef ENABLE_HEADLESS + void GlobalActionManager::showPlaylist() { @@ -1214,13 +1233,6 @@ GlobalActionManager::waitingForResolved( bool /* success */ ) } -QString -GlobalActionManager::hostname() const -{ - return QString( "http://toma.hk" ); -} - - /// SPOTIFY URL HANDLING bool @@ -1243,3 +1255,11 @@ GlobalActionManager::openRdioLink( const QString& link ) return true; } +#endif + + +QString +GlobalActionManager::hostname() const +{ + return QString( "http://toma.hk" ); +} diff --git a/src/libtomahawk/GlobalActionManager.h b/src/libtomahawk/GlobalActionManager.h index e9a96f3d6..d28a5aa39 100644 --- a/src/libtomahawk/GlobalActionManager.h +++ b/src/libtomahawk/GlobalActionManager.h @@ -45,6 +45,11 @@ public: QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const; QUrl openLink( const QString& title, const QString& artist, const QString& album ) const; +public slots: + void shortenLink( const QUrl& url, const QVariant &callbackObj = QVariant() ); + +#ifndef ENABLE_HEADLESS + /// Takes a spotify link and performs the default open action on it bool openSpotifyLink( const QString& link ); @@ -55,58 +60,62 @@ public: QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename ); -public slots: - void shortenLink( const QUrl& url, const QVariant &callbackObj = QVariant() ); - void getShortLink( const Tomahawk::playlist_ptr& playlist ); - bool parseTomahawkLink( const QString& link ); + void getShortLink( const Tomahawk::playlist_ptr& playlist ); void waitingForResolved( bool ); Tomahawk::dynplaylist_ptr loadDynamicPlaylist( const QUrl& url, bool station ); void handleOpenTrack( const Tomahawk::query_ptr& qry ); void handlePlayTrack( const Tomahawk::query_ptr& qry ); +#endif signals: void shortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const QVariant& callbackObj ); private slots: void shortenLinkRequestFinished(); - void postShortenFinished(); void shortenLinkRequestError( QNetworkReply::NetworkError ); void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl ); + +#ifndef ENABLE_HEADLESS + void postShortenFinished(); void showPlaylist(); - void xspfCreated( const QByteArray& xspf ); - - void playOrQueueNow( const Tomahawk::query_ptr& ); - void playNow( const Tomahawk::query_ptr& ); - void playlistCreatedToShow( const Tomahawk::playlist_ptr& pl ); void playlistReadyToShow(); + void xspfCreated( const QByteArray& xspf ); + + void playOrQueueNow( const Tomahawk::query_ptr& ); + void playNow( const Tomahawk::query_ptr& ); +#endif + private: explicit GlobalActionManager( QObject* parent = 0 ); void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q ); /// handle opening of urls +#ifndef ENABLE_HEADLESS bool handlePlaylistCommand( const QUrl& url ); - bool handleCollectionCommand(const QUrl& url ); - bool handleQueueCommand(const QUrl& url ); - bool handleStationCommand(const QUrl& url ); - bool handleAutoPlaylistCommand(const QUrl& url ); - bool handleSearchCommand(const QUrl& url ); - bool handlePlayCommand(const QUrl& url ); - bool handleBookmarkCommand(const QUrl& url ); - bool handleOpenCommand(const QUrl& url ); - bool handleViewCommand(const QUrl& url ); + bool handleViewCommand( const QUrl& url ); + bool handleStationCommand( const QUrl& url ); + bool handleSearchCommand( const QUrl& url ); + bool handleQueueCommand( const QUrl& url ); + bool handleAutoPlaylistCommand( const QUrl& url ); bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); - + bool playSpotify( const QUrl& url ); bool queueSpotify( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); bool playRdio( const QUrl& url ); bool queueRdio( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); +#endif + + bool handleCollectionCommand( const QUrl& url ); + bool handlePlayCommand( const QUrl& url ); + bool handleBookmarkCommand( const QUrl& url ); + bool handleOpenCommand( const QUrl& url ); QString hostname() const; From f520217f5178c3eea15c1ddaf9e8e40381d7bfbe Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 8 Jun 2012 20:07:01 +0200 Subject: [PATCH 338/433] * Fixed XspfUpdater for headless. --- src/libtomahawk/playlist/XspfUpdater.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/XspfUpdater.cpp b/src/libtomahawk/playlist/XspfUpdater.cpp index 22c43fd4a..879184ba2 100644 --- a/src/libtomahawk/playlist/XspfUpdater.cpp +++ b/src/libtomahawk/playlist/XspfUpdater.cpp @@ -77,15 +77,20 @@ XspfUpdater::XspfUpdater( const playlist_ptr& pl, int interval, bool autoUpdate, XspfUpdater::~XspfUpdater() -{} +{ +} +#ifndef ENABLE_HEADLESS + QWidget* XspfUpdater::configurationWidget() const { return m_toggleCheckbox; } +#endif + void XspfUpdater::updateNow() From ee76eb3dee003fb4847854e93bed09d279709a8d Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Fri, 8 Jun 2012 15:10:37 -0400 Subject: [PATCH 339/433] Make the 3D logo the right color red since it somehow got too pale when I first 3Dified it --- data/icons/tomahawk-icon-128x128.png | Bin 69076 -> 69076 bytes data/icons/tomahawk-icon-256x256.png | Bin 266130 -> 266130 bytes data/icons/tomahawk-icon-512x512.png | Bin 1054090 -> 1054090 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/icons/tomahawk-icon-128x128.png b/data/icons/tomahawk-icon-128x128.png index 8df40cb4a1a606f4aa890912b2ad938d58f685ac..4701db23a6fe2f85f7d3d63eb69c74dc82f03137 100644 GIT binary patch literal 69076 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 F{{eD@l>Gnz literal 69076 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 diff --git a/data/icons/tomahawk-icon-256x256.png b/data/icons/tomahawk-icon-256x256.png index e0793782d9bdab853821bc4a0c4fe4c47737c3a5..559067acd273aab127a4bdde419c21b9a882979f 100644 GIT binary patch literal 266130 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�ia@^Y85Bz5>5z}Ru{u1kgl(>2saf!{t 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 DKVO=T literal 266130 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 diff --git a/data/icons/tomahawk-icon-512x512.png b/data/icons/tomahawk-icon-512x512.png index 6c9757a3d432dc77ed9fd9f944bccdb54e729e38..14db6cbc33780fe4b64b0ffdaeebe0edcd8b4ef3 100644 GIT binary patch literal 1054090 zcmeEv2Y_8g)&Jc4+V-B^^lV5%5_+%FdlRGziUJ`Nr4t0PfQs-b`~ea9L{Jp?q=R$_ zy#`1KA(ixOda}K|ef{14?|0_Tdv`a5fB`~sXZOCDIdkUBnKR`~yL10=!gr4-E$UyS zlqx;y$U{$5%7)Wc1z}iS*Gx|;RdUvaha7UkQHLB-f7un6o_FCzW0ktbvW_fyu@hlO z9(&;>m)aFdU3|&7D^5J(;QH^Menx#{GAINWwelp0ZqYgWy{z@Rx zoj2Vxl||pQ?T%dQxwlyw5IcRhFPm1E$(0q%>g9(NhxZE)9|^HaL* zAl+AhLAd+UeZF>YCpg-DAl>I)e95`MA@>RjTv3P^WJ;!Re$8zt1lWmZrt`KoIU2JXJ2t{{UMiLeA(HT z{9GxWXU0-hlx;nPyvNRa@3F`ByX*k*=gfKob6D$luxvF(=l7({tlCL=SUzqZcIo{} z?G=S=ZqLKcxm&3hf3H;EIeFOde=1degHkVi;>k}f>&pe>#$C40jyqm`_0>CEICjhq z6ll(TEnh9UL>UedsI$ixpjZqh< zi`5nCYV}L?8+D_)S>3MwqW-4tQxB>~)RXEN^`d%Jy`|n)6V((oL(Nr-)H2nm+Elkn zS(X*CO08U)Cem z)7Hz@Th@oxr`Bw%!CGZ?SV=ozm)JG-AbV?jM|&^(Ap02mWcy6}eEV|yTKfk3R{O8^ z{r2Pb3-(*~M03{?_K=8;tPwfFaB%se~LdSZYWNaRF!N~a!AP!ORg%pwdA3a zH%n%hbe5KuZe4m{=^3TtN^dQFr1YKA1*P$_>arcmjw(C1?7Fgh%3dg&TGmotSU#fs zpzaePFt8S=zpz58fCDnoIVbzCJkE#A$^@G*#RWGXv*Nm(=s^%v(H`hE-Gr6X% zPgS4Y`kdP5nm+gRd9BZ)+Cc5rwMW%nRC`!#Ml`VQ!O zVBfKQ|Je7bzBBqJ`_=b5tlv-j{i)xJ{pR-%_TQ%e_xfMm{~!I|>)$k>X28A!#tiu5 zfM*8G8E6mOX5fhfe=+cZfs+PC2Mr!{#GuOt-96}?K}~~e2Ol{2Cxh=C{QBTkL#l`D zKjgw8cMf@D$m;q&^#|2oRR7odckA1R4jg*q(5r_2Yv|;msjWtCb;?%1-Rh~W<_{|x zw%4%phTS>r?O|=hhYUY%_%DY)Hhj*A!V!CoxM0Npj+ihaw)M!ZPuu#YtzX=F<;cDx zj~aRH$j3&`8&x{$fKiu^x_{L4(c#g1jsEHAzmJ}>jlIq8+gz~CJ==V;t-b9Y+g`Zs z-?#mAyU=!fZ+FRd_is0A`;zSs+Wu$TKem0t4z)WRyTfmHcyWi89f$9D#*Tm5al($- zop#^pqMaVxY3|NdJ0HFCZ+9NQbH^^*>@sGTdv=+=Yw50s?|R*?FYVgC+qS!n-R&Q{ zeYSh`?#JzZ)9!EYp4ns1J+9c}$vsx>IegEv_Plq`S$oy&b;4e^?DfIkp}h~@`?|ef z-8-?*9{Y^j=b3$4_uYQqpYHqUzAL{o@;hU{^Wb-u?6=i^XYco~{TA(CzyDeL|8xIE z2Mj&n>;vvUVDW*&4m|h3e;>HwpwS2Y~qMk4tev?z@bMR z`o}{jA69kPDTn>-umy*2b@=&*KX!QA5xXDpizD7VGIZoINB-%^Sw{^zYRplO9MyL8 zo=5-c=y#7PIp(Be{&vjbW4Af>ietwgXCHU;aeqE;-gifQ_mc0vc)U9PsN?^9{QMI} zo^bgIuY523y%WB7&-a#}xbum>JaNKF)hGSXf%nEkE^# zr#^CO?6gBqyW_M)-{0~3zxw{f)BB%(;ps1(5jo@3GyZ)>^aqFi;4eQ|_QTzOc;gRe zo;mW&YtH=eNBw_v(T`sHaruwW{_(SCh0Z$dtVhpEpMCt<_n#d-=cse;J*REVA!Gh` zOyju+o_puHtH$m(_KvYD&fD+2JI-5q{(k5G`TSKE9B{#17c^aX$c2Bqu>B`T{^Y)& z#D04GPapcJbJ1xRJ#}%x#b;go@+DQ5{PdD{FCBd8HJ5&R*|wM6c-f-M_qqHpm$zMU z%oYE>(z^1@D_Ps$w*SxW`C0txQ?GvZn#yY~xn|POxB2-We!k+` z!>|3nUj%$mzj^B3u?zG>HzhTe~*Wa+@_ecExu^Y>7yyC`LH|=}Veg6~up9}wI@*j5n!`*+# z{_)&DesuFrH{W%0`j#=beDwcz{(pb{f6lGv-8%WUJ#PEQ?cv)mxqarJ4*1iGwKi=8(mmmM-!@G97>%RXj`roVmchO&u{p(A255N2NyVHNW;BPbT zIryHZ?j3mVAMTC){oKD#{l|g-c=EnM_uYJ7@}C#}^Rs^)@vj%|-}?T$9tc11vj>(x zc737usID z;KfBRo&M6NFCYE#+vE2g|NJXEyz8w zcAxb8$Gd<0{Nz0*zwpVPpS(0>?h(P!s=wsQ7Gv)kwVY))$K_47jW{y4v4{#^?OF1UZ;=!H)$+GEjc4Tm;NT71&t zxl6_@XUo~a*4^}U0ysRv^P#TYy55eS5M9uHad#^A$9TW^!->5T6OyMTSEQ~^N78@I zjLwYD9+REtTetb!4YIhgT$&s#ixHdeF(&SgPXs*6V=b8(#vx1bhkj67VJ9OTd?a zF9BZyz65*;_!96X;7ee$m%v)~AU69v`x*2lu%$`h>ul%FmL^<3zrF;%trGY;JBDwo zjC{U*349wQ;BCuZCG3TNUHR~)Z_+e;tS!vo__i+rUjkpX1ey{bo^H+pc+xTr)C2OJ zz65*;Y$6iaSnYFT(b*8OY)oapF==fG?>>$%fh|e`UuVa#MG4l=tS^D}NT5f%3kHKK zlgTK@`O^BX2fg*A%b+iU`#Ge(bnu2`bVG0q178H!#PMxk0$aQUHigb$i!TIU0Gpiz zq+OMlm#f`&+fD7e@4jmI@ZlET{Io)$5EZ?ZN~MTn6%-UGyys~t+g1}k`Y3bFl~<-W z6KMpH54#`oc7fH>P{pajNePscl#3XB>)MSM&b*@mw+#UjU<7}%1W!OtV}gDG?3!PS3o^i z3T&jo#~9P5jcwq@UKiYiug_*)vT8}AQm;IrR0gCnVCLCp9reNs+4V)-z%b^+vTa)i zO6hc3Rz?6@n+!J;#-!JVOSo@*32a#sc=_6!ezcae02IQ1(=lvWLiBU%OTd*tRaKQr zCX*Isu!L+>Mf1Rd#Z}dP>w?vV;Ybaxf(zl^52O)*mW<#g!ZP?v&}c)@yjeUJrrhO# zm*eg*UQ{T<1jCTAO(Tb2oW0@9#OD|)=`5BhI&r~BTS_VXD+|Qzj8aKl_t%c66NzV> zOvY(RCOa3jw6@P$yd-wtyYI!CuD-J4bLg93@@F0cqb++TG_1`wmwv{434BQjaAtbI0SBl(_SnN3F=B+m5|GB{$FT`b(k?6kJFLJSF~qoc!VZf6II-@KYVWY2 zIs=xYA{Y<^td0)lba&$>e+(Id0hQ`%Q}L!1DjSbsP9DG*U}H9G(863Fg9|)q6~fRZ zQdz44rR5sVS$HO$$`%zToXQGE1##XXn@OmGg19QLNUNg4v??r2SmhN-r?@Ddwe99i z)@cEg(X_H!;_1w)xMj7*ExThyGQDzYJlV9Mq$0MUt~m871_{Xt6Eo_r+cN6Ghj>n6 zeP<=){6U{SeK1zaDh>$TLNYeJ#%*jb%taT=8}5bsZeIeMl>|0sPqA4E#?Q=_A%UZh zK3ZYcsNQ<(tuK|~lN=|4uho>-E7cE5eh{=!6_k4=>}o1`G%!r|@ubq#s=d8jH8vI@ z!D1}nm)YI1GON4W%Er4@GS;b5Q7CpOaVr*wjRy)>!B#OScDniC5FG{wRE^N}L9F>_ zRl1{9C0d(QHkII{d?OD4C>9I=vY41-U=%7UQ=zg-Wf$^eNif`W;DD*9NMQv4!yXPm z;KxBnoPfl}MMPP6BpkwEp6qa8JXBVdunS8%GofHxwz#AVgM(P6u&7OymUOAIvP7o5 zqNzJ*FY8WcTDrTtJDQ{2Ew9g+yZpuj_gjTjArLWZ>%Ryy50P?iY#ku^G(?~EDtNlR ze#YtTUl)vU-}n;vc1U2rUysJHU4J8BEgZ9<_{NvO79#V_3PKq!XZ9&;DHBP zIGwL2x0_l_*TdqEOatn7u=Rcj0Mn#?Cnw!!e7tI=hsGlkw@Uc9rO8QAy0|74(z^ zg(|!KRJ88nP(M+J8JJ-deo@pt-z{8MyJr3vW^6-ceKv7vEUpTOqUV-_*FgDW#{d{^ zva~rMaA6#v(2sor;XhbfsUp>NDu6+SQ&gxN9HdknIFytq8;^sN57}U_+X;pj+XW@f zs<^Z*6$&+DShOr&ShylNct~@yI6{fW7Pq%GPo6QO=(z#>-&P(;ce z+^?S0;2Qh!e+I^@$R8t+k*^0UE04V)>sIq!2;}62De6W*< z)nvP)h1pnlKy`K%sMgj()zlQUpyV+KP+2JccE@d%7<-J5sg z?`?ac$Y81HL!K5R+GcP#F;E4ze%AZP^s~kbBJVa^-WbHnE)7jF}q*GFqP!;&-S>L{0s-m(vo3&Oa zlBtHStkVF`;-y(@`Si+~#>E4w;>+7R)6YHfV7I#9Cm1KJv5mkH3$;w-|b6ala~M+zi)gAY<3bDJ9aGJ$yfM*`iA8VO6OC2$9^Cb zJr=JALj@0oh8Tbb(jSlP&Q9oc^U8&fqkD`J`K%Es2#MN=Aw=aQBP6GMHxyiBSGvrI)^CeJNh$UpGFD~Qb zMEK`Na52t)_|fq1PCI2#3HI@!>^Zw12=!Zo2GLh_#|Pr(njv;HIskk4McMXNmF#R) z>88~RGkj%tbSY=`YL#5JNF|zAL3d%F9xvzRwP26_-*K165sZI1tf!suYxS#_%85r3 zk{{wyG2>6PwuF$Z3zNjCXb>)0B3#E6;yHW?bbs=3bv$5-=4UXe^k7@VB*``58p5=7 zx+b>E1qsqfY}ci;Do`fMl>rtUY0%FffeQwHkONZn7>o&kBJnV5kEn2Qxe8SGQBEz! zXV})Ua3PaZR*H8miaYE;WMw8&v^Z8$(vT`HYE2guc0>ycS1lkbVK(-4^sydGd&lihk)DtI%<6+alJfK_}UYPIpCGho0;QmMNxk`jqdNm)Us#9vk|2>anRm3hVnLt**||*{;q3nP_Ju+u9P6jr$gyVsB|xYWWJ4 z!qh+B-mFqM#V058(wNfX=iR6mSXmf8I2IX+ckBlbV2x8@FyHGAW$W))Sd(t%V5Qju_ zw7`cZgS5OoNAKl^TzpAG78YD|H(Nb4WRLuFSYR?M%L7?=?qb1wy(0Wk84 z1YX$Grx0mlxrK5MV!t6=TCDSmK{^@K5?ocQ!%s7R`i&Lc)Q@SDrvs+T>g{_Ii zs_s-OI=j28>Gn@PTDA1IzsItH!upOF3=mbgFZPA@JoHdIVcXf2O-=GRi4^r;@4aY*S;U)!b60mM@Q_7R^_Q6%8uY(gYQN6X-mK&(nJ? zEtyOw*7eg#E6c-gI8})E;AG>TZXDAWZQFA?3zmdC%_6lP4V4x(tx*Z^BLqqkpq!g{ zL;;idXGBrLjNcoN5TXfr&~oSFu9B9N@{xs@rVNHf&oVNNhQcAKX*%G-jqgV42?Wks@=v-Rd1;P7J!iBVC`b*jEudf=_w@-!rEtnGgX;=H z5j%wa1iPwQS(R1FDa30Ep|A=Rm8xJ>UDWAQ*OIQQ?Z7JyDeORWV?Z!vX=U|$)1vYD z&wTLF>KDep(x#?=oKg)7xo?2`2xR{NRY#T#I55EKLpk2wh-Y!{F?sYp@ES3#VKa=z zNJRVmUta>>kOVv}>l@<0Pu7>fdL+=dZ(lWR*f6ykYw&aD&Rq|t4jR+c7P+aqd^ir7 z55ZdhF!a{L(R2651$KkgvZX_x+;@X-ODuY=)U%a>Q z{v9-wnaM-LfeMumH6uH4?G_lJ0wW7rWzj`NMtIJM!s7&2l%*R<^frEgNqpkKL7mK` zL{SJGH-#JxDo=!hLyb!{?$RI>^dzqP3u@Hanw~I3-h_tB4_VL?{9GPHp_308B9KJS zv`k)!m&cI^ZW3Qj{+R+Y@8*wbzzHV6AJY}T1mmEA3`=+x06`%P0KzqWm0eq>_Yru& z0LCdUYtQx{@@cBNW_7ZpxHVQ)wWP7KV*a$|=0z7=`^)+2$;Y_a#1i1X0S5xTjl=g3 z`R*a!LDYOnicD1uZQ~}u>t36mFyHtR_{t@~O6?n80-KBkc-cO#eG`68KmByI_uhM3 zL+a~od~rwp>wyQH2mbj_bCOGNpy&frTbuiqRaDiXcdo%g@Cc~xZ39^~8prgvb2{5= zQf)0NyKJd)@Yu^%C}+iT6<@wsB|4iGuD_Fa^!T10W{-Mlo2T{yIG(R!n&>T|?|OA>M;89YL@R(Byn zl}R!+msK5yL^V&6EPPa!f+RfZD4I{=8LXVs01PK?jy9qEONMl&Ay4?^lp(hdP+eHA z6bxRu;Hr&0yv>M`!oV(ERjYzShGUr6PdOEpc3d(wjT_hE%D=7&K!4;D2u~=rw(xo^g+KsV5Zi|4zGY_0S+{RDa z7~=ZIm%v7mKzP~}cl&>z4X#`c8m`=PSJrl zx{r(Xx4|G_C#dfoP?_toPv1Y&)L3qHXoIlDTWxGE^HZTv*U3X+xNf=#gMotA4pFEA28cSHGit%WkBdUDYuMNb)wZjP z$wN*rbBw{kgN{ol{(6vZZR>j(VW0JjdZ7yu#+*De>AhJuyV$|)(vHysOQ z)gV|_lX0qRy3_socBcCETb8JQwj`!*yAjJr3ilU? zu((>lN4_A1m4Pg7JE9OdaL~fkHr?idQ;Z3x$LrRi{;w~AuRsF2rGEv4eUiQeHbeqg zM#aQCpw2$~Y<1UNcdb7PUfy4cYx!{P)i#*%?+B&Oz5NlYt$nbye8oV#BVZ?&HK+s> zeg>}#SSwem^wI{EY-z-`ws=V&d%`M={uxXCxNIL95F7mHti8Rht1E;L0~dVD(lBG)c<`VLx_?Av!$Xa9b4mlYL%_VUzevu{3o%o4R~ zDGw7;dOR<{a|ATpI^af<3Wmd3-bw@~A2T2@BJOPiC0BJ!7-7EgC9qK?fPU0Bz68Er z3E-$;-?A?2ZA;!AYEB_)@VSk%}63Vk4JHx)k>v!p|| zdN9RYxp*2;vZ;9zHng8fdXjes6CezF@R&q35|fYw^Km4uAt3w-mn86Q%74C0Wx$im zzet}lqTxVLZe~Kgz&nW0-d467`g{qlaa^`g4j$ryhe&up{fN+r(IX00*QkQ|#Z6_! zr8Dcp#j}5K?>$SFRFutq-&PB6df@)$>aTb6`~dbM@R0|s2tB>V z+X$MraZ~8V4QCItE_e?l-{VW*^CX~K_UB>w;l2bmk_6s)=N+uNhb$=lKoHl(HLP5j z*?+g)%#2A=se-D0t-HNyXkpo4?Dvm`(%;9*ID24pFg)AYUYuRFENCrVsllniorzgA zNO3t``y~VJ&$=mS1POPM44r&@s4f{>Fgy38+T8Llg@_#TA_Bf`fHw`WRlqX^a($x;l$5FfZ!E%rQ3tPm+BjSo96BOx z^&1dR_USXHt)zUyvX0JKbC$1IG@-d^`F*dCZ&I(lZeBCwLO{`X>g&T50|sX2wKS&| zFIj@>+T|S(uux3F7`O3L_Um#p%s0LSdPt!0uczYP><& zd!uUHIDBtsJ!XaD494-ST`=?ChqHe4e*IKS>kxdfw<^70u8L!}pIp39Vd+j2rdi+i~^_=PiIvdD#*A1A%qxXK^o(B(t7Qi12IKl@ms(xx%dj9)|ZzdcX$ z>%o8?6lfex%S+J{7fziX!odajz<*Dk+;A_Sxxqk>bbx5`nCFT7BP#w(KA1XCWpqIS z`1$W${;p7@nCR95qX6Y!)=IElz&oBDeB}vaOWO`s^-;n8167~`cM+7~HN?t3EAWOv zTe7CQwWFeZ#&pMe^X`wQOdo&C?Tu=61DC(3`1!ga3z(JEF2x%Pxa}Z|uUPdS6d+je zh-)4LqiqbseB(>tOG&`nLwqR$ek5N4>yiLES#{M_SE*ZWxn*4_0$&)o1+rT7t1$uWeJz>>O-l?#XMNumz`JK z$s=JVMbkaXBDwxSkRBXpO{mqRakE9_#s*ZPq5=#x?RSsv%K(E)RYyQ>u__=Dgoy68 z;gnf3DbS4{IXXz2S{iXU7BOy(T!{Jkr|eh`TD-1=r923t6nWyGtN9{h0szIzfdz0lQlf&j{gl;zfO2qsVYZ|! z9j$s`q@H&fr$%Wvm$ z_Qj9cv)1DDK4$w4mimzbh79Ns*@43#R4c$-KTRn5OU&$aA8%&B?Cm8Ae#CA1P`6oV zow`O>3+kdZK@22Cog=okH9f{Rv?OuQj|n4>;8_&7>vokgp*jzeCq&>sVEEU0fCNZ} zKsS?w6GEPdPp=z9FpQsnEjx~enCq|1@T+ojTnKItZ-(*(j}?p&Q1__xJ^c;dOzN_WSH)4Bbsk~39MfNZcSf5k{{|zU_&Kv z(@i&Vb(CN0F&$EmsCPO}{6hy2pZ zmZb6J9Zb5iwpCbY$%FU0<;q=l*6u6VuHu)Tot-$fGy8KfIWDMbUA@Tw#)n@<1i)u3 ztvDGbP6>m{rKJ^wAxACZ;(>$=1hm(U%Xo$_x@la^L+(rx;0Y0^&t0XY>AKuV9yE`L zBI)I5Xm$*k)Io!^_%HOBr1*`)&p##anlD-YZb1nVDJ#|kDLnbw5w-{78D1kD3>Sn# zeQ+5O4!q)R0z3s+9T?K?jNE2Lv`_7vMakrQ|C}-Boqs;?@Derc0}cZCMI+i|kplv| zq_{ZSlHVGj(r4}BW884&V8-pW>GsVQD1qg_$ULmnhMxtXh;nUX3zV0i<&7kPi!QoI zUh(_WpZ>H?iVcp_AMf&yLMOL7=I*J7AdO%Oa6=TRi3s+ zeC#cO@5$nw{cr)NvC`q9w$hoGwNh@5T0&S}`Fl-=56y2@n z(FH7CgCqT}(00>uX;GWYbRB+SLKC5fig{f|_+ctK7tD>;R>G3|BQSAm{tQu>sp7{? zz@_Eq|7$FNQ)^g!tc)mUW1}3h_{IT>CjtGARfAwzg$fNGssaNBD+dP*Q-!5-x@!AP zUp;W(%#Xw2Pk#OIBcC<>`L^Yt!M6&~OvI2Tjf0gne!UrYTk-az++cv=-bZj<7~M36 zhW7ctz63lHSa(jb2U*UmgXtCcmvvR{cY=Ob%uDdp*L8H@ho#^>7CIL=v7$5;m zUSqpniDkH82&v}M71iO6ZAekVb-LmcWU{PvjJ8R`q~hmai^wgZZ=(EB7P3OXa%CCv zV@G_$0Q>v6e9D$@MWa3k3QO=MqCv{qYPgEm_GxVihu>>VtLaS{YsG@brX@E%`{eAV zNs|_W3{6ROAP_98tIM>-V(He_R&EjSF)ISb)*07u#-rcB=%?xJ*HHg=iuemL1*Uje0$7o_(_CEHhZMMpR*S5{=_&aqO{KUJ|gGgPW! zfs<)&Ol4zH3$OD9R1uc^BL(I}Ke{qbp`apVa^I0vbXNdKS{eaWYoTIw5L z0vjZO3of`om6n#O4?p}+z5VvvYmL+DI3uywe-P&H`=D}dXLUt~s`>LP(z9l$#5~OS z=gd;+hJ{YL4Tt_RDa$S_a^zJ$=`g8;q<_LhN~$Kj9zUI4B}NXkD%Nm%T?I(p#^9XE zDQg#^6(H#|Els&+M@d8zplJbD$n>VY#@yeNhO3z+H;9MqFl%1k8069iGQ)r)KkjhC z*t?Bg1ElA^3RnU3s@JtlrvWHEq>_`uNEpRm9~QT zs$pnQy|VC%VG6IcCM#>_#0CzTzq+t!`rE5ky#MoCZvR9ro{!I0NV0{KTP;v3o_=327S4AhouR~Adu-1Uv2r(pZ;buf&_6m$`YU8?W;m!ZqvLv8uLu3;jc#Zg!lh!ombCR2PYe90&< zaHz@*7?f%&Dw#Mtoqg$})lD;=o;iKVCyzX|40VaG6a?^|ZDjbcVQN`dS8_#bYbujW zaxlP}Xa)szuWcYexG`S0f%*1kE`fFTPMdkg{p_t@0e;DZldYsb*!IK%L9 z%0qG5?;up7ZB%>5XfJG=~XMTnRLp^gz@dxfkw83Qgs6t$LsnoYbYpu|G_0oU%BURe_yB; zeAWdKaUj4tgrx*!mlYIbI}!9-RUKR5mNw^pnip%yJt$(d7etIx+OgO~i1_-aowi`!Ge zVIGG@mjtEnex*kgIjD;!lv%SVPxgXTujm1_$`oB7x)V^MxP29sH9AfS0a0jJhEtb{ zZWd)h<|PKzuj%5%p;4KZq$XIz6?LQ2&=J`e3y-AbqG_7+>T!T@Odt6XzBHo%={%5S z59=-+AuL3-ix|ZB^S|YmKdX$XpsX}<8dldYe9n+HELdKx!h?n?r>>uhRaC8RFRz}o zx}b3OTdgf0{pyC_eWco2TTrR63zw^=Sq!^zhoObz0^DoJ9TqTy0ArgLLfg3E?BS;0 zH=DKu9=>^ z{qKXfmyd*M-%G7-8Y27sSn|(I{Zu7zE-sTZ{+!bQ^q|2r zq+lixs1>@Vi(e1Rgh^6#xU7;*Ls4MxAR9SQo?;%v=pGF5`1z;YHm~xRK{E5i62|?+ zxRMaxG|ZqGVfSAy&4^(AzfJ|}hpS|5-&A8b^5)F$)EgfxTR!{$-g#s3iYcEgLR8*9 zR5}`8>B`!6dhY7gN#17!*xCjKtYjP*(9mrj0k}Ve`DQbeK(DT9Gt8l%rS(dH9nQc0 z^)L0n0}m)}0rWOA9j9ujQU_xN;7C-K{ZxDVFlWx(K=uexT1k8g|xN8M=zpRi2zgivn~VI*#B2kyCF`kh*K)tV!_bm8Ae( zhxKfV=>dWCn6?g*#L0uiWguB{69q$pCA_(A4FNv+6ibu9ulO0jNScP5kh>~C1RY3+ z7#+vB-QA9-}8%El5P!NWVO zIgy&8A}fxM7>4SqtyJOk^V9fXrvf{}dvELs^P5wwFrcF`l*|St?C$nahZ#`<8T`=Q6 zSYGXm#`bg?76y}e$v^Y{yDB*aU-D^dQt52Uv2eOy1q&4p`th|UZi-WsIa=tobnoQ~ z7~$;3Ts7q+kAZfE$f?f}?q4;zA?G zk2`*lU`ZiI5Y*hX-29ld%^*jTB|0JtCfT3?zMH&w884TfKr|SvZ-4ypocmuNKMyr+HJ(UiQBfr7IH`Cdk;1A1R{_i;0|fYKvj)?q zF}C*U-&|pMfxi12lfbX~JcaME{}*Qg$TJt#RuASKY0_D+?>O zE>-FfsQ6=5CcB5TY*~f#=@gax=zSHNfj$2v3sX*a)N%?70!~2$r~R=4z$(=1YCnoo z`Yujj(1%Iy?aJ7=-5`OwFcai~X;6;~StGumf4}@UQvGM0qmf$23d;kxsCZeN7r)C_Kpu_qYZM9%_E92ndM+pKIMMZKCF=(&ttN;fA z#PvS#=KOT~=36d-Trc)5&xg=_v#J_+MU#Oza+oxE?mRPwW|D4j1n&O0 zw1jVW03ZZBxNDH~#+MZQ{QKpP3WNVIT>qv1@Q1aGgKYf8y0a>U*9t4D0->5ZuP-W+3376@YNI1jE|n zo6T4PRL?iuaD$pVd$x7|gAaPtlTtIL&!`--?KZpPouXr*{Et-4%_CA!{3*QVmxAI? zES#%SSo+5|0UaB6nerw-xMg~suQ;9o0OiOO&?&J?GG5ooeu{y>5hUGh5vEta0o5~U z4lZOJ7!f7d{nfNd!!;mdbh}NWb#tlXK zvxOW0n1h2{3Gl84nC$^(!sHCj9&Y-5^DU5ou07uZMtv5)xCCa-oT;j-ssf$pP=@#G z$3`vYmxu2a8u#*q?V!?+#@qWxTgmiZYTjI%Oa0MzUsnlS>6`6n=NC_KqaQjde96a> z%YAa44fHcLA1$LwwXM4W>DAcPt)*8mP*JkF(=!7A?zbC_4jY(A!iA9%{(H=nM5}Yq zpy9LypPefez78T7hTHYvQ7jK#>B59CBWqOQ98NQOFkll(;xJ6h&%a;(dMNqL)_+z< z)J0ZHOI{^RCbAZ;1;9;%b_ky-43^a>XW$Uk*0^98uF)_X9cM@-F8RT{{#fv}pIY76&zUqyrQUr@ zMW;=2VoMj|Rlm4p6&G7}Q3;iuXg%!ti!Nqfr~vbM5+{(@8TP7Bt|DiER5W+y>{0|B zp+aIgB7krb4j8pI;kiMF#u6CGQLi&pV?poppZXkO1}gN;kEElMWGXgQU4)1 zGzeW6rF~*WfUN;<5oE1I!V2RW;vlvNGPQkGqEElhXi?dUMbYj_|DO8k^Y^{QVFrEHHe3Si0C>Ou zs8OTVi1ccAv~b_Tq60Ylhw?vAwYG1cojFYPN+;M=*Y~UOaJIe zV1yQF>)x5YwAO<;B`S;eJ!eCrjMw0T01p*(7*MG|b@ha+Ff}E>L>UmnjYCD^Ds4?h zM`lmtvO{IxT^_3A)@F zpRt9o#xrpY3$9-^xHU`6kH=`9{rro#T$xckx~%>3XC2b@pSqY;oQ(l* z4`7%9h=Y|p%js%YPHU42VZdKeTrzBUMPXho%POiX zEe%6S*l~H25HBW@QvQK6=cn5kQ)i8B;J&?yNx(0lO{_q^C_6I3N2KQFW>r&zbNwDO z-Em4sV7VXf{~Q7E;i{!=Wa`8BRP627RN~_gRc7_7H0Eq}HUx#wlm0mPhgSj7Rp5Lu zBCzvtr_A(nI^otAcT!Fu4B>(bcaI9?E@cW5!#qpwOn^#HW{p@;V7we1Nk{rINf$^! zfK%d-rF?pbq>}_~akz2W;hA)4GY%4Tk-ce=Ee7`t&&7d*e0%+X=tT(vVZ8ikW;9&* z_ORjS-&1x{mMl^hi7uC%9NjWxxo83V<^N^sKjbOmlRC*-&htHhIq_JUTLZzO;&2ET z3|V!9RI;XTS5raZya^p0FI@Nfn{O_k^6^SU=7B+O4cHY01*$Wdl&gk8!)yz16@V)M ze3+QAb;243u%{8w=bMcsfsaU#SX6`S>`%5-)(Rv~Wt!Ar$BQq1^9`)gWk z)7)0nmWJV1{0v~takVHM@F6 z>4Am|V-k9xz_eXBEXYLspsm?rm>5uzxJ)>o7G-E640r#1K1x(;?^Ph@t9G8caMNA#{0l4e%ij-ge2f!8Mp}*#usH} z;lhPh!{Wt^mQzvF=gh7cI%4aC&{~g!T0btkXi-gO>L)5a;eD0hb$=@sW89u~?2-~3 z3g#goQI)x*Mde8!ktfRToyN8D0UE58q{mG}gDZ^TM{E~}z9(lqPEjKa5H!P<_8`8- zq}T8xL;xT?L1SF{#mDX#ev^QUATWt&cwz)Y9Zuqr9>E6Bjq6(Z022<|gh?EDdiVh} za7OX-?+T8x$UAf8Dzfv-UrR;{19H-mqW4SHe~GVarKW*lY#<1z<)peht#q_Q*&WTQ zYC!$qvPkLR{zC?TXW)QS2WD3{X5SzGqPcrGghK+jtWc$s=`?2ze9Rz#WVs|@Y`Tph z^Ez=2@fN$m@$GLw0{#Ht8xZ<`n`AeR`Nq4u16609nO4s|XUN%YnDs-ge-E?%6ICj+ zqceS)op|dN)ji>Dm6|`7Yk^sZ>;Hu~^3QMka@OWZI~5&j*1kPWRT{0#c!8}|Dx{Bk0+|dx z^_fgKc3ZO@!bL#^C6%hKvQMO_uI_~E>Id5omzCDO_RN2lE>0$!66thn!nVUh`t%8{ z>gb5!?qS|G#M!?Y2++;U^YQKxn7ZONJ>3q0m-_1$-U1p8orjNueK$R2a!KNaXH@)!r&SDh{w6zG zu#*?D0tH3N3bMF!>Rcg)1xupCW8Pi!4e;=1WFO@m7sCd><`+wdUy zm3005LkxcTf1Bz*tFim!>a#fTRWO_p=JtT4y4qAElMYwlbE17hkr9K3)b}kOKBDcT z&t~xz0-hcWrL$R1D6ys>?S(YCMX;{6W8hxfxDm}aU$+GO0l?QS@h_3yidC!dz3_^_ zy~y?2#WOssDS+Ui_}?w3J;`TH{aWJULD$Dy0?pxcx|EST) zw-zsLQnBt%MC8oB0PhlVf6-3rcL}}11XzUXwdtnG3s?L7->+E${&v9EEbt9Yj>~oY z(hp}9{p#w_9`j3VvmK{=E2WM>;hh5bVd}Hl#p(CnQL*>lRNXTsXVRVRmQ_+}+fe>^ z@ehk}c;}Bdg`mM{jm3?7df3X{R>&6b!n6Y(1ZtRWr+NhuFn8jgYrTTRo)NUP8qdNO7Iw) zq%?w{=F?-OTr6S;u2AyxFXf^|3HfQE`{fUTd~55!v?sSEqI9ir0q!2o;9?=X7MN8JnSOQf3FXEP;@BiQjs-u;k`pg>~`WuNu ze|**NG!^aMF^QM{ldrz4Qj%^Z##zo2g7JY zDMC%={COZ<0J|EIKCf{Vr~&m%Pt$c(ER}GMPA(mt1D!72U?)#QyzY;N)8n!%cqU!i zr0JD~@%OfS$D!ZPzequs1Lcty3SAJPU;f^@MWKlKme+sgfrTr1NyHtj4cMVReU%zG zRJ9gYHY{w9&YHM*@zlFNm@uKCvwarviflU)%VuMc2QL&bhXpw};7S1>Du3Ff+xr1X zV6=U+RtcQ)?rz&FwXx3vFe!gEV66iGW`Q4k@Bv$kje&p}HLEF;CYFxab+-d?BIh^^ z1ddZnm-bD3h%f#;|CEYP{)i|49Sg7g*?8w)1w&|y(q-qGmMC4oT&O35fJk$f*|k=D z^!GsQ;Q_i!rx%`hd%-*jxlWTFyaw0UJ&?U=(oH0`3T# zLLn>;q_Hs2XoV9ARa;p*q%>SKq_%JMUUkPDRd>=9sksC?)+ zwrl*s#(Fy%IPnCB{RyJmvFcsfKQ96WK|!0mT*wpgh0V#=Zt^-X=mn?C1`Hk4xnDZbehB=FCF{!=~m)Kk`Xzx!QN`GqYk z{|~EH>MRu0d8)Z(4>e&zIPu)ms_V5ERAR}3tb;4N0wraZjo1EoAvo2vF{0RAPfm%7 zc9a&z!M%j?*Cd*U5T>DqW)B>RD{lZ0%cX^7;a(I?9D)rUgF_o>z|x%3O`dY;8bqO~ zf820d!Zg!nh)~d@4^25j+e{+10089@YKmU}72r4g2zx?y{ zN7oipXIOu9n6dM9-mSf?qo|^rPW>m(u94bK{;fd3asmN6lS(?7SX2emNvk9j zNS$=jNov-tS?cJckG98+8<*=Zb{Rdwp4ZrXF!uh>!TQ;cG7IJpO^tt1C7%0_icOlJ z63r`dD?rG?X@C8GubVhp3{)RF7tWqN&4+MKxed(qBRzIG)Rq#+9!OKtmi%g3(qS3D zCp812O&r+b)NmJ3ETNN2Pp9Zc$Y~DZXbPYtEV;yl9OG!Z#A76lYv9H&akrTKQzBY` zI{&Vya&?KqH*%7K$opMcizcUJ*NEe#B{bYJ$*l_I%R{J|5|HX7$(j_Uj6C&?em4s0 zpC-fN^~+!6%!c90S|sHbguq0UUvvG}#i&b+^#q3lR3M<7L|oZ;YoN$dk-DP7A-h-i zsoSpqpt?*t6JFTT+=gf=oD1MR0)Z5+BbE}^w0gffsG)2Ax;bAnV9SH_ZM)+`rM`-@ z0F{A_!&Uzr&q*Jye{##=GXKpLuq^vif$BaOUg!aKHh_rbrmZdM(m_>7 z=0jXBJ8TUUT>=WCmc`D;2a5jB$7gM0OtB^T93R4ohbQ6ygA{aPjK`?VgW&0Kal3Ga zYd>j!`|=OwDH&$cNM5AnW?h0P5d2YG#6flm=8qed7eL`u_r^4m1bLEA(XkKLhV>@L zFhKMh<8c}gN>eDw$b&y5DdhzR@N;gsgz%PD{zewxhWzW2MA4?xSu33igbIuB&4D_V zDXUgZDvR+aLSwUW*EhRNJfa|TN?DW$iZ!Q0TsEjQyf9IsRHo>MHJo*! z2QTnz+6FFZ>CT!xcHZcLK;G}VL{aI;f-W7tn;uirH1g>h9$^bbldi$kag1iyyt--R z^7bvxKQg3cfjm%IQd|V!p@j(;Wv^$>;=&JhgLEJfXrwR&UHdoYujVO7ksq4O;6WwA zFA7V$bGro26I@&y99WLK+48PheG%aVZw2EZor%qFlPjM z4+4N9^@DXp*Aqf~vr#0Vo8U$v$s57k0$3 zMZ35-#%++LCvv-Q)9i8yvLQ-0j##A0t{sWf_TrLOj|>{(t}SuM1$l6J6Yk+>JoYX4 z(_FZTd+`{`%nB|o{BMf+2hWmY^64@te)@C>T+9fiKmZXrlh>J%G9;X;UIqd15DjOv zQ~Cp&}unil8kv@)gt3bR98@$}=CD6v_rn52t z;6Ol>KVoM=K)W?9p@;agdZ1$xn}IAh2IrDy%@ooaW3wrLo$WP$zxDOsEjuYL)>o9W zg-eA3*e0;B8W0;$uND?nOuVOI=_3z3`PloAK-5S9?<{37c#NY0B>4bN#n06MGZ0|q zHLC!uC+2}u4E?_OFC}0a-+xKQkN$ZQV5i9bt*xz1ty;0d9yxk+u6KU+_tzI3a_x0{ z;7H%uSYSOxEnZrjeGMP_q4J+Q!%4-XT<%wPK_QOTuw&P4L0W)m2B0naQv7iDDp{sa zpaC0xytX%-`H?uVH7!t=bahVMzS>2TK}C<=T(E#|*rT6u^66>18bkO(kW0r+r$@SE zT(V$j=pG@LfaHyeNK$fnrdu1~U2yXLp8WKb53wW;>>hmR=#m%LDSW$bEnh@%^G!#=WN$ zILxdd@EB_rxExflCLpT&ljp|d12u#NBV{6)F*yR9QrFpqyH}>Z>hhPm#JuKN7CsGo z1oy0O^s^2VL$WLN$lz#v`9+?9L&CHWiGCed!-z$|HAHNc3o zw@q@JxjFR4GjRjM`p*Jf?_BraN})#u{%?u-@z*Z_v>xk?H{MVOAAGQ>(dtvjDIKlU z(O3pJ6|s+UrcNv5Xdw3bcqh7KUN#*H*xdX_3zHr}S{;)yCFf2m*+WSGB9z%9n%#H`roZS|SsqSP_ z;Zts^DH?U=wzYPz>W;-AJclESOepMRLimC-v@4RPbhNP7w8?JHc<^#Cx0FP-d@syS z#i`w`SUR0yeukBmm5i#YDyu;K426QK0ykBaMk1;ZBLmzVqslN+z`+(3=x$e`u2vPm zs3nL`SK_$1j377);uruDQ8r|TQG!`!z0(c>%---ODaoaLkq z)^wZ5iIdC<)F5p(^&PLH|EGK(J%j>hC(@m&Lls6lox z(xbQ`gagIx5yh<`CL#lMTtQ-M6;QsTqF);wVtlkUmQG93B_tmqPg^4C0AhPljN90z zN6h)%beLUXm6?%|fhVaP(QhLE%qA4L76UT}#bpbt(AyA){L9o<7-#O$C2C1AmzEX6 zx_zak1i`wSmHqCVi_RqU<1{OCX-Gl zaO3He108I&#$%aPogJJ`nU}JWM3lU(>p@U1jBaC0evED4UYqP2!|9qmu{#wT5l=_) zB6uJa3_2y@uqq0Ntq2r6&a0{te5eA0AVc)iMQ=_?d$YiLC;Y>vVRBx-0R5j0mw;Ee8y?HY{6Z37AK18h zb)dGcjw4wy_}t&13Y`4Iy#B|kv1#kngm+cfb5E%FNAIgFI(UoM{h>pZul=}jKt`Ic zG&0tG@uPFp0EBsGz;5es!`MtbPIyF-iOoJ#x=kXu&57NF!PhRq0*nFp%^{Euqp_2Q zacKydo(yZ+2FD~Nhy=pWO$#(YRd-dS>!FiNmI>jXd@xwzZS4FrpPI1Hcax#Ti73*~ zI2LEdUv~6=r_jeHZWtmrDMEe zv!ga}+Pxo!n@+oMa5!AKbyZc-psH$BQdF2N#mYf7F1M(_J=X=DEp}NtURYUB7%VL= zQKc9lm12NUhyhkO8By`{Q(XJysH4FPLpF(ti}e&HybJee+6JeCG{oosJuj3 z<~w!O;W(pl`tJ;MU#F{;tB0lDctu5D!gqeBevB{uB`mw5(#EC#TFYSCqg5;!&|RCf zLO4O!ZIROJp#ezi6(nKT+awsOb*a(Sc|334OdQ$t=lRC~hhq-WcMVeEtjsw$3w%f0g++ZSH#UcgJ38$k<%eyA2u>5=>-A1BnFtOoh*WJ`RaG_6 zDhSktinD#gg-#i6mn%+ose(i*fWZ|emPN9{fLm)7hEfW5*WxX73=DA4AcL~upg_OB zNETd4&;d?8b&Py#1crGHLukAh2Bt%Fz0>Z^w*LQj`DaCBG2m)J4Dixv4BNUo(&0ob zR2&RjTNRep6$}}8qFviB^Sh^?eO_ha%Uimm1(*yKa0LllT;8&w+gk#3n}?;)JDjl1 z#|%pT>Q_pw|17{p%B?>b*hqr(lA$8`%U}MYiYh9gucY711$Q~lcQDT%iyreRoCNHX zdKvHkz4VNVEu2lYZwJaN6qE(Jb{@7CBMk#|a!o=25=0d0c4OSxtLx3fO?b~9kl`kV zcCRhGCrne)=^D2;9k1K)))QOP^JdQL&T-28N}FeY+ncJv(v$Nd^P*GG zShCM-(n0yrk3DKAKAet&zOpSGdp4~FC!jbrNe99zURb6&P+rSo-D++}qgvS14tFBi z7KkLea9?T?%(vs~D@)qj(=8qCdWMrsW>t3=nKw$Ec zqKZF9&&@q?2&18G9sziM42}nsb82DbG3eJYZ5zKC5O{4#FP%wQ?cEqHX?%tooWQ*9 zSoe%%w!KeREKpw5rYa&4D}Ybf6~wy&LxOhsHq})XgNln)4W5d0LKWg8_aO|>aQ49p zgaYmtQ1qNt&J&G-Lf^z3K&18#t=>h*9`9oW4xZ2hJp_9#%IjlbWIvYgeIJ^ zd&K>^>wm9Y8Ga1E^yiHiy0-jF8Sq?yv|S4yF+tyku|PB%R8gxK-w~)UEUY`Bw)WJ} z_fJ*7e&n&2R65p#MiAsc0HcCJx}jac1a-}*cWm@e(}@ci&E zAc4mpe_S;*G*~0c%DnAcbvn+$II49CYWDGJ<}8(Z={eQ)#>*rvHY~=WMH}xj@^B^2P)Oz+4&FdS8v*8;f~m;4 zYRKFZ8TMvf|J`hgOpxD=o&Q`rmIPe!qi@4|fsWlBwF;V+tHGgQ?FrR=PYa%YTHxBp zAAeoNx@2ph0JjZvC6j1=(g~RQ!BXL4+7BtSZm`5?8?(OpYjAwql>i0mn~f-eXPSU9p&T%wdPIvZ_}e`@iDvoP5S{cn9!D5cpB*!;e%F7yn1!eNDwyFL$z-y#$I& zc(t~0VmcmZROycB_soI?MnpK+LQEM-#Rsl{wCWUc-X9a!*wV=v+Bu*nMsJw-wFV{@ z(>5r%J|q|24KWCW8@G!r-nF0^zI6CT$iFL72uC!(Bv0a8cHzg;xzx}1+IX5BUqr#? zeu0Vus~rdR+T&@=Tf*6v!jkMNgfDDwvnMTG>P%~FjyI;$F?^C~-C8?y^m$&ct-Sy1({h8mn z`EI=`l_XSpRdw^dy#Jqn{`qH~T>d{#o;-PYcdsRX@esy*r@|FSD6jN(Nr4{YAZ3b@ zbb30$Q{l#lAGWm|afOBVLK<<>WZc&Zo1q62@Aee0G*tZb40B*`b4^Wx4m)4j*TzgvNgYzg>i>e4E~E$OyQiyxRsHqpnEUZ3uK^CEUAuOy~j1KyVfn;^PTp}>_o1E^M3KIUyMQMK<=mw12RB#Xwo2! zEd>Zh8%i3#xP!5H(wQgHfs?3#X5*Ke7JGU6@-SOFwHljbXG z+*n52&13J{r9rniIOZm>{Qt^OFlHu922oIb`C204o-F2{H}K_BY2 z9K&kG7!r@YjCl-+ujOgvMQ4+6{}{u0;;2V#!ASE>>(`)qUQP(eQ*!yj$cskD2Dc9n z7r@sp)R&XXi@A|E?YLm;YqxDHUw~#PFHXA>4k_SkwRyaf$+qX~hb>I}aQFh&dN_(W zEO-fUh-dKJ>i@hjKgM2=@o!oO-HP?fdd8!jT&rc10C&M9ZhUOZ#MkC(*M0okx8CNC z92iGod7@B_iVQbSO|(-D9h+~y(D>8$PNIAJIap5U$E2M-ZfCpndFRf^UI11~=>2C; z{jA55(s18>_ucNh_urp<{Ez=QQ=|_(@#yfYuXyPPptb(EGc)t*<{h`W#*Npx=7T?Q zjmC0{7ie9Mn*d>ua9vDihCS=UY8{IS9IOCwp8_`)4my=)^{fE&lL++*LmnY9X|aov znnAZo0T{BpOo$H$)RLPV{KR=%yy;<3IhlwO7=Mr(k)P4^Gh;|ba+8emQXQE=D8LL1 zp#BTkt-pw4_Kx6dD347~yS+;*ox`r!n9dc_rxxbjLlfi8$@w`cA}Sqv8EA#6oTQ*+ z@CC^$Tu`*$u;dCVFYzg?e0w3&u_fpgr*JO>OV(<{>BzH|Q)@7;7iT#3G}H{okhpw2 z0U%9bLg6&{3dfNAjKh%{tK^Z!Ji(hAe$&MlZ+h*PEkm0y2dga36fPSmZF=$MEu~AV z*h{cd!|{hpxV>ySe0>`;HgBM4{MiXZ1#~9|y;VX6<^;Iz`@dRqJ&k`-IV^qnj3&(pt`HUHg}DpJabd08_Tz>6jKe|#NW8wRykuei zp-c=uqwD9j`2t3Y+eF%uKaMf8XZzJcF|CvblLj{N9mi32Pt;c2f zoS1hzj~%NYS;RB_Bx#|7pioj7V=0_CESv^fMp}3;B(Ih-B}+VUm`Y5th$|1mILz8* zShP4SoUj)M$!Mg29W0CuR^2c*sHOFq ztKofiJ}$uFO*plvkU}u81wR0x^ZN=~hy6c{$!t8K$X0k>0Gt(nJ&k{><2=WIr?I@4 zD<3=HwmG-$E!Dwom%R82x1-g(zj_TeV5e$2Tk8ShZ=bF(MR1M{m~z}Z+zn$SqGa=(KU!}EO{ zQJx>b1~IHL;*tG)JLkp=Ww#3|=h?tFS#+@@_`)1DNHB>ALBCoF=VYOOk82%f{3y> zhGW+oj^l{;wiLsn2^XYcCcYMw(I%8p7fs<_C<9MAjX%SAB*NQ~365vLMsj+D@v0_X zxc~=@f8brdXKJ=_u$4{@p+8jcD&iZ)Mz{a;;OO=jCj+^yc=KZjM?I8^vXT*?m{?5sq|3ac%`$mvb30%jvmO5ZrJKxJT~mo7rp2mwba%B;mDz6 z+PPhLe1j7rT%nT7RqA+K3Z0yVVF3tz!F)0J%P|nUm^Y@M_jrE-@GQFkjrG0v-s|@4 z+n2<~A7B2V@&7&a%nzsg_itUnyZ?*Vf7vx2-OWRP@;NL);?^G~q>b)x_siKRvVj#8 zj7ooCIKA)~5?{-MteVYWOe5awLhWZ{ zg=0v3El)#C&$zX48g+z8Q>4cgr5T{?kj=%-1$}yh4 z^l-Dew6{>6-#R^;j5KS>%gXr;KfZ1ImY0rfa5$*QGZ0>_qaFue!l?F%L9M0X}J3r@+%-7uh#ZKqJM%upj z_+)GMv15%^8!wo9#lfUhAhB^)SWt$YkP`>-5|87A$8_?NPEUE_k!%@#hDDoi|R{Qo-PjC|&UFqVH(Jk*Pjx4^;l}9dU)&{qA(t+)jVYh{E z?(k6o_KNTrd_F3`{vB2%%L@l!V=z#x78zwo28@+Ift)3`h#-n_r`!K6iSlMT3W`Pq z!)L+xM=^O3XmP$El202rK07xz;f6=IxR-3+fERCy?`YL8txuO6-!=eS{CQmtDJlMzldA39He`xAg?(eUHrbz~izh-c6< zNrlC)aCkDWl+jH~ms6rb9-N#gcR>7y)IpXsie&o9OqK-fJ{QWcq}{y?UaZN1mJ0cR zE3g{yJdrpn=o;7W>kehbojz6oaOQ$5kS++*OH+%Ba7{r*qfQ-d-*NgVYHy?5cOq_av(l8v;6pkSkF&$~ddm(ADm(eDl@EB?` zKp6W~698P8h4HAMgu6)d;BPFq+w3aLk1|UK=jYm=-Lq%<#!|8RvSQ%^>>s%J)my6r zS71-b#%3p9EtGRO-Z+=X))2fE;u=kSvjP1OM|$B(SVVJYrvD==45G}uv+=SL0QccA zW)-ns$G^XU@%k`dHsIUc^aiXo7aT zh;I+%@S!1IFE2T+2I6#t93!z)TueJ}@%{wh88khY`*`OcjDMCAj{sg29s&HW+kas5 z^7VNA4`=^35AEwDL&G=|bpSd7%EDe9r@jD=ZrIfunWz&H4d4@FR`vKbqE~ALF`Po4 zMJZm8>4aHM6hrNUh%5kFV+-o14Q~vUoqNyX4PxL_W`_$3p>}CzEz`XWnb*VC?w*2#H&g#wc zYIs3eYY?X+F|KhVKFyB_TAPQWP7%F!z+J%a2JxVEH|4KYXhX^ zYrSynD{>rHa*T{80=k0U(un`Of&B@oXYr{#kZk^ULMWHedouJq3-Y_2MosJ2VUUSiUEr&KF<|G;X0xo4Ts^mEXWzu!Usr(aI#=&_8 z7=66ThkORGsc#Wq-+Kx-^^YtpxhLl)+c;vjy%VqS?ZGlXHya}r4Jijdp$s%mmtSR= zWxQkK&j|yS2%+K$=}8wJhb5o!!dK-BI>U@tnN&W730aGT@(L5mGmcK-7>XXlUVN=E zY0uR8KIBsgUkk=G;tEq~D=a*Q#CyFAKk1qb5GqWgP9D-UAt03T7hdGVAn?R-^}Ta5 z6Ywlo>6-(UEkBnG%)hyn-|&)rI&xv5G;-0%s2juC1I48|n4*SjCRj((iWoXH8iQfX zS=lV%Qq}JT(RS?8YxRF?RVE9(=lb}^^|7LO!Fa@iW<2#``1YiQd+G3l_F)Yt9MyD}DJZc!jNn0Q8GylYQAx~p3 zz$enb_)(XbHP&~hQ3HGxfV%MYxl;RL>s1AdBGd9Bj`Gg#%x4)$+%kPVdgxrhs*M14V;XM z%1)KwFP20MVeH3m+Xv_eaoazHFUT~p!D14h<(p`>+!MKSdS9)X-hK3VYtPhF9be$( z`Eazjy_T3X`PlLkmvt8&&jMn+mycmte#ulGf-DC;!@>!vo#=)0a$}s~Pz44Rjv-jG zxL#agLOG_5U2iy!I~_dk1>zS?Fs6$}*o%ust1g_7Vfi>r?Jqj<*vGR3;+h#~cEB)a z0Gb6D4&gRaK&2=RAzn>$*w%}s_=Np zq>c9sT{}U5-%mz2HhXX501Xw!SvH;^6pq*A+o3xK&&%*L-liUE15BY4&4?&a2ZKDp=dYYvPb-2<*VDiG6xLT!o1clxusIcDSW$Z^H-r!mL+ zmIrFiw}C?E31sK%yHnHvEfx;}`1r>^&i4Q_&hQ-Iqo}|S<2k^V7>c@AxtI!`a2g-bS-NvAEcBEzAhKF>gZ< z-|4dl{J8BST?#=)J2vJr@}e;;B|=(^Gpu|hQ}PL=Y>3md1BfnzPaa;R6q2B5Rsn(M zWH_SDDLxJpCtWVaPeoJQ=|Z(=%zrAH;s|^3wZh_)q3;cgF5}Oza6%ezg>~yM;~s}O z0idC0oZ%2uF6MIBX_A!jnMd-n4hc7I8r?8_`S9?_tBUyx-@IY;l2>iroLq*OK`syQ zEFn1^eEfwG8{b#!QAAA6Rgu_-CHy&G=_sP_Nisf>jvn#}lv_ zql1k*`39B%4;8BJj-|#efA`ql>ko_{;Z8w2IG~iv;Y*U8WehHcHI_L>HU2p6H1=4x z@<3OO7lzLZ#}40jC#eB;#Jlgl+fD$A-vbPX0PsCPzx^LO0BsY%fv3`BXb5k$3~&~U zE@fsllWszshOzq1h_5gi~tbAT12Pyw!Sr!ssNbF^Y0J%ecz1I&>{!&;7V3ZE6P1Wft z*mX64ng0w9@&Cc{irYCp)7n*Qv>sYs#*uzgorR@E8SB{CHgQ2MJgk+0CX_-TWLW89 zoN=P}8hyzij6L&>y$rsT4qHizM~0q|^piox(GkX8v>5i{rxT8OtR+c!299MqRl2p} zVw!M5;mke`3-5)rrlJvF%hTwSu1Ns#*zk)^gD#`LYBc~2Q^w2ajOWCFo;Z1$Q*$%N z;4Ak#H~Yx)j_Fr7)8W?+;Eu*v>(YG9-jYx$WPdXqDCC z`91zoC#(tI)1ksxLsm7cHR?ksE_}V4cT??w#&Z55u)bxm`p&{juPFT&?90ST04D); z?C_~l$>9xbw1BlgrP8s##E#>RUM_115PVq_bB@FQ1mF}6%#Q%{p8b2myMNtfe|%#O zXZ}{u2ZKxwdv-|c$DRh;hgh?5AXsO|kME$Fg|?s#0qd8+-byNBEeDK~kkpSBX0WR7 zb`vlvE0qlfF^UJVUYH1$#M3AjWdCo_@-a^Q*bIW~b{$5wkpDU5^)qd_L~tkA?u$)- z9ajMuDOZvX-tU`)5`A)|mF}Kj?A$s(-}=sxBhB%-SsG^zVi{u@T!jf`^ohrYU51`_ z3UQq1W2iVm#<98L zaLoU7c$|)S-1IRX%ju=ZVc}~*(&Q;mIAJ^i=nZQUK!Yz&ou>(aCIy-V2-48g%jlOO zi0>Dc;Yp`l>m&CbKYAE`=oN!Qm;dY~mt6ANTzT-va-HD|lX7m;@UR=iYXr@u`3_bQ zk~EKZgZ<#89$;@bO9z=O_xU&epH}}_#duAK`og!paGp@xVG`gj#;Qs(P<(6iqV36l znVm_FHdY?Q*+J}wgIG1p;ggZ9Q@I!yjgVtcj%n$vEj)T=e_!{1{NjIh?lkrSJWs{q zpy<0bYJi^tyz=s>|KE6xvqu2cs(=2^_W(N` z>wLYv%7~EWA@u<@u{X4aqXV1q4EovZcX#4o<*<0;3%xePdmZCh7(-oSqC@GC4;2wJ zq}^u@2&yC&R$@R;XBs*mig=8`ADfVvPV=(3qM#JMU>aefb|E;)&4jp~A_nphDt5SB zN(M@mWHC43o`5dC4bS@j>BzChm-g?ke|LPMv9!EI1D$!i_tnJN%VxBZ7Zo%OygZ)| z%JVa1{3;2dy#Gpx568ID2uhw{@1#MK1eSx70>P6_5U7OcIZ0p@DNGoLiOU1c9BFI0 zlhMWdbn)VQw$L~K$y4{{&#-7uhpTSH7emz_X~JWu$rx$G<96xA6(-DZ2(~uG1$N3< zp(<8j;0!7@hR!Zfhh~sbY$jTCU_lF<*m^uhvJWsC}!%={+Q6Iq}0Nee0fH3~p{Fe+4=97U62O&zM)fF2@D6tSS-f4JRzj>1G}5d4}QsHV#d)inV0CpqGcS$x2ing zx8%M6e#n>%%A&|1I&ei9_+&;f#%@~hhJZm|CeTb4H5WePhZr9ET878-*Q7OoE&qjz zyKZKw{keljo7W#Z-neu8cw?cqT*n!(G_+L8RJ_D-Hmu`0?<;618fzM88Fv}{#XuvZ zUkFg)7;+L2d&-nN%2pnx^br=+1VH6mWjw$~qqCN$f|6%nqwfui9z(F1i)qA9$DJBx$C)Inm}TKHOJJ{_8PSUd; zEjL@u>51C%{O;Mg(GJP4=6J#l&Q#88G`69>Yzj6U;^JvtnYLVbKWXL|1q%81t_czn*E`4zaqFz1I}igW^PEJ@(?NTfw*;h^u{M z{6$lk?MYllzPJC8Zf%YWh~t=F6T;>WF3cVK-o(WGp{13^QhBgl!-@e8ogS!SU(0Z{ zisuQ~D}a-RP;eWE{K+bV7>$?4Yc!7hI6F(nKQ5I`mFW{IrDvf3tbRf*akT_zf#d0G z)eR2d%TI;k-C4S-I4$A|o{FI1PZ7Ed?!9K-q(fSv|@ z%RAnYTyXKl$p_#6ehy~GZ~tC#!Nng!Mg1;50&rRFhHL%K|ATn#4~GEYwLk1$v+w?L zcik#!)?rssRtFHTv7q4}C80_PkIOl5LJazU#zU%dG>#DGffn$)c`_~ep+vHDUa+Ke zd9w^-Qoxm0kVPsa`U(0f_E1Z`yLxId z{rvtz&2Jt$vNAqDN8=kST7ExNhF^x6cjPksGT^aMC$33=AZg?kpC%B5lqb(TdhhT} z>4PpPLt>W(x}XeC3|U>h9wc+3D=bKQ-*sz1^%2*X@ZLDqeH<6JMK7*)i=ie1f^nM* zk0E+6zEIhnI9T5~-l$K0cWUO?Q*(1mi+G@&9~`OV2k-(R_6H2$W%n{p9`4|rDhR^a zIQ}!D=;!{f0K9sl6I!Xe<-rDKLLg^8=d+A zE=q!nIl2DhTNXSgxRbP-Nu^YDBSRw&dx$O>Ycwl+78h_Efw7y%i9`w+lTW{L5$$j>-pG`jU;SZ7bU>r(ZvvlP#E-cO+XmzHhn{9OQ_Rvt`3eX~W4-sbxz_@XB49~h*ASeV#!I;7w1_mw1 z5QM^Ez_FYPt-`~=HfGPjUwKPR(Sa=zil|KF3Ahn@eolY<_asEnmy8g9&r1LC3gDo2 z(_92RS?YILxx(6_IO#JZys^r7?Y zw?6?04gTLh^(pt8zwsMc^WXC2FATop6|edrD(K(2nc3IYzJ7ySyyi=;@%SV76d>LJ zp!Y_QX*?e6IO&SYpfUL$4Nk`C-*6@ak_{2!A!zYFC!;a!5&l{M7)xg&jUPW2N1~@% z5-~9^_J89sd=+019B52$jDS81{|h4jNyWdH!e38hR`$Gt&+@Q=CmAYMTn&DAC+Du8 zuXV0GI@!GT;Nj+;$%%R$pK<|zY<&6IUm0i_Z5j6Xu0CGoKN+sOe@+VGi2#j%JON;S zoN#0-5x`~qdlkP71R)hkFN~E-jDt0EC!=Q!ePqoVU~lYos!PHcC!c7&Fm6NPG8QuY zar>`@ubM0(g9dyP`&3A$3_2Wi-O)Z4j_IYN|yvyQnO)6rsr$?TfU(oV8F0c&W`wgSM#I^)@=`fIgAA}*w>QBdU-Ftr6VH(6G0c7- z-DVBU%gU2oKeP3+D3%9#=i05b0&!*B@u#JVJA{*b?^|l5-=3TA+%i7iI5a&CgKG!) zu!sQi09=hKIpR(^dC8bF2qs*(zIK6yjUm> zZ*oV9gY~PY=WqG4()1k_=RSt7RKLA(%gt`_%71i?haYU=vvj%K z@FJAfC?#kXwgD4}f#CU>Zy6vi2-2FHJ8kr}&!XaIrd4t>VoA zz8zC)HSjs34u%xpdiRrhj&>02IyfddbahcSLSNwVPi0_#C=|6ruk$qN8&e&oLM)wU zrxr1l!n8z{M#Mlc`QZixPfPIJAHVH7P7B7~;lbgd!q#ouN5{5q>)iSH-U(FHVgq|F zP>+0-GsTUG+VYu<=@T!g_X3|~_`eoE^K$22*u4NO`guJWn4O(<_uO+&@_WDcds#Cs zrs>aMBJd}ew!a6FuJ+|Gy4v^eb!h>!a%@21*Db>Hf20XL*ZMDJ>DIq9QKA2`56LsG z+ozBkY4A&`emx9qocSYxXhf8TG?-tXlB0%mXfayYPpT>0T;TEYd|7>_h^1Uh8+ZdC zjh@_Iwm}R?8%+#^;xMtvBzFO53DbfK4*N+5N8Q8t*7prF3+`WzO*XH>#=k?e({+3U zK!(_iGZJ$NRkL&%buHa%DPJ4>)>`r>jr@8{ph*E?JQ?65LlXj(ffE4vSeZ+~_bLru zD?Oc{5BcA+rXE10raG z30J@A4U6xrhv)4C;MlQaZfas8_r^E9Nsa5~)AZ$4=l(dKx(~Yh?sJW=TBVq-LE6$i$tn=pb516 zNTMzXAn>vXpmf<0Vxa47E^%>IQendQ; z2oPW8x%w5-Fl~LI(;k0ldg{>q3rn+jbe$h)ceV}`OKxCzgc}AiVj8%M#b!Z1BCx@S zQH#j|$E9~K#P~NQ!0c&?y&7R4cvU1B=)6Yy(d$3vV-?|lT&Gb_N{tmamd{l#*tqG! zvF#V8cO5!1g_VLO@aC$;Vv#EXz*R&+D`(G-;#AdwJ#1%Z@VuM=u<38R?Y88ne)^}? zxNb5{FCKC3cVN1H-97xsVB?yr+|r%jZZ}pI6E`&Iaya1&U$C;qH+$#1fjT{)x1e$F zV5Bi*ke$R+41)zlD9E&!5D5~;lee(Qj%5D_;L{*GD+hlWM_wlLDGgcOB?Av*f?Ou@ zK_();I+>?+*^R-H`@A?^v4p75GDt(kQZif~NNTx4vK#8{t8*)zFC04Byy?Kf`qbjQ z41W`+`nAHxd`RQnxgZU;CIB+#TI$z?fOOHsLnvcUcq)T0#Y-r~O(@Skp?(qLAg`h` z+;`_j4fug@;_3g>Q{uCB-q;n$P}jy=J2?z(7|(RPEPB~wdJKp zCa0EL^+q|Z3~wxK+?=c881f1p50pFj`T&+6;h+R;?3oha2u0|OkAIYxS^NJNQvdPd z;ZP;Ee*%@<#=oO@ok8w{qOMlPH3Bc=L|N7*;?|m;D*WAH0-Mj_w|D!T~+Z{M`QS-WM+|n&K zx|Nynq*KCOKR#E%R-oBE4)1fz=l7B%NRcc zc=lfy9CqWSA@_~>W%s$m$2(UaK30Ete0-(d!btRY`!u>uj5a&f4|uP^myxG|kMHbb zTzCD1nhZ!z?@~YW)!n|JCIBZ>(yCWN;XpID7A=eHBj-d7#BChoyf}t?y$nb%l))Ed z-&^HzC&~|7@ijt@C=RD4I_kp1D=YJdo9%Ht7MRWF@>M(%s0?A8VdVfuj-S#BeUl?H zQb~{@!t*lzS7pXhc<1vZPMSRLRV)yGpGW=2ETvSjUyJpKT5Ti+JQ5f!6e`=RgBO*C zM_b=NbZ`=J)EBh+T&v8X&eWbH)Afcu)zg_3ouCgr%imvn>y@8$?sWG8d?NjeXPM7w zCp)iZ1f!#)?wV__O@8S;?_rCZ`yt*Ty&N9_z^dCv-LdhPG;t8X;?38&+Tnd^S{dL{ z0C%87tsg8kQ^QjGxj28>-4W(E;U{>T6ABXU2cE&z>)Sh4<4>B)>mku_26CW@ubOu6Vm$Ax}Rzmpcw%n`Q({CUJi(t z0yG04)GUCoS8FSrT`YKn3xd>l=TQxW4!-J&;S3^&j+xa;)d~7_l838!gj9M-aS2~O#;b4E>~>vWCq`U zyu7$w6(*!xt6%t-v-FqmwwyO^Zf?$9cKPL;^l;F*>;J$Z#SNkI@+yyC^=(0Ueh&2#gArIWxMJ z)FP~>vV3cbW#TA8*AWtV(OEH~GAIophZ4(SsOP~ETsZWk?N9u{`hN}^C5~f-^UkG~ zyLR?i^VXx|jfvT58DCRwNNL6&l1QhK)^mVf1FkiG#tSEZJYlf4(;$cPG{GP)#Y!lp zOQ-=Z7++wbs7Wyo z!{8?h>tL?Jc$F~zshh#mS-9oE{^mS32pqonqSw4`WaH>71}g(wN=;X8weS`b_Q7>v z?DGYD%ZR3##j)vrw`8C^>+z4YUI%zhBP~d>zkHARU#}y4ji_n@jSQ-(IEhuE2%gt+ zdbav6=qpx5>R$)wv{!1mLC{~4ls3L+XyE5-qoc*I&duG0T#u%OLen)GY!9}d3hgWL z#0w-(uUqq~dYRU1m>u%Ga5SjD^h>{#y!JJ($r|y~-@5gu@W$>(+;Z)IY2JRTTe|+s zuC`})C&lNzunNarfNWfBzOhAl))P8N7)tCazQ1~6pwnj3hd7{~$w+>5+9)+De)u0o zZH)V96UJ=G)6LhX@i*-jXB_-7r?i>`XJzpjh|Of$^+7hL8CDLy|JKcikJcBL7Npep&L2JlkQsg5oySIBck+Z<-(L&Y zWPlR`dCF5>ngmGE64JA+>3!inj$jrhPRIDZ>({`kYJj7n*R9oWL{pz*8sUO*zf}LU z{t5<*gJRC%eYO(rPMN-bxYJ&Gd|`R~fXj`ixqNQOxs8Jmi_?d5_}W$uhZNc%HEs-8 z1~{NOh|TlY1~kQ)GcI5TEeiUncl?u+(nu#7#26OjdLn+w5~ugUEFt4qJQmAtYm_k1 zEhrxF8KVg`)XVRtIfed%5MI9t!1EK_wBTT7JD=HA(zIIcq}#`5=jU;Hz~NTAy#hWQ zT*^FS#W#RoIq2LUqE&yndFOYE zi`U@&zX$H)ZqZy0U!lN80PD||Kz%zGe)|vn)Pc5g$#y?iJtOR;G!Cu@V`#=2}I7tnJL9r^f zw=XG7NH2q;zDTG(N*H_V!$`#U2wTWZX_po|?c+~QPaS!5ak*A(wuW$fvT=xq5r@I&6x#aW=(w-NSfj{_z zKS-{);)<+V4y5S?8}a;~j{(wM4_0f}T*(r=hHGk2GT9U@Qgz=6J;WdA58e?RKm-XY#;PAGG=sRw3&p@$I8N7 zf(wQ6C7^Um%v2P~q6Wwi`#UnHa5#ST2kVn=q<~ld3#H^>uH?R1>!knl(6Pq9Jofm? zjNksRJ98fPPh3WucmFizGUzn$GW3L;2xt-@I(an_h#v(|rdAc02NkC#0#dHA!j&Qg zTc#82;-WC)`mSFC&!z@!e1wF({fgn3rf_fnR9F)NhS{$fZb3n}F$~*Cto~h_!*_}w zpPs2N*KtnH@P^{xhE0XRQZZk^*L3)GF5K4gmc~XeM{syJU;{oB*nnryxEJL3hr^Eq zFdV1>JA3q>*JZXif-QsXw1Tg`jcwTE2DWVN9Lg1^_f3vd=kP$`9F7&t<76S$v)T%1 z)`r5>rVP_D?5oIvXV=d;JprHrfA_oJ?OyuQmu9VU&pmez{@6vAd3 zy{p~&4cAzlO><*oSX<)}pBzDcHHo<0NM{mkF!-BiKM`OIhYM2Z{+az@bw44+I~iC& z>z!RAZ?kK&xjrohAPZvIds7Svf#$m$mjakR&`Gr7QZ{6SD2r!#EG?MAs9*sg-$W6Y zqOhyr=tm{wuveyvsq!W~9_bVZlU*>oIFHkP{?O6J9S0B9aagwuF~9H=FaOh6(|8MN zH9&@4lLCbquStT^Fg*>v41bmvXr>?msW7D+iL>$qfm(PiNLt_ZYv8%oKzC?+Nxfmo z_k-Gph$}3pKFe^1BS7QNm)dgpus{(@+x!$!8v~{G;7aY-W6Sj;Zg`|IHaNItC`k$x zEPEGIe0adl8iW{(V;jmC&ZZqW+@EIrBatsHFD^ZXpMiqFPml!hZQlT2Z-_~Ku)^khLH z$tu1qy%5i01Dq#u;;Da9#k+sYl~MN{9P#^^!^hLB4jyhiJ~g?5DRpd+bZ*t`5snkEEDx zMul-};iRcQ$B;^?#Uln`**PKL@aEW?oLpHxe#gx0e5EviGr5wj)lR2?&k^EXLem8t z=g@?39M_iaX~sXf%o)D|y^t!zbO?amLomFq^&g7IBDe9y#-y>58^Cdan<^EaEIjg5 zD_uA`Gc}Eiw3Pr{IjhX7Ex;I8U5KVIAuH{a6&EwF2mG9!0PNVY!+rD*{=j|a)1S^7 z>WPV|ci>YV|9euazqNDgx7_k|Uv^7-AMUhpY)w)wKb`=Prd0qLe;Iy4Dmr=@ekw*8e=5vaks`Qi@G4B$cl{bTlQm$2 zF=QwmMA(ZntbQyQPiQp}V4U@RtOnSGKl@P;WC^Mx(i=)>*I;@j@Bv@f`VW^Jt{OTX zx($|2Vzb zxplS|fMw+?DCeq6=4WQIhMP^(EATOZ_oJ2Gn(n;cEr0VyxAgc!X{(4=0R{%p-))GI z-}*Q!g@_lxb#>pHc$-+m38nHpff(!#k!cwNq{Js(_# z+&Q|@$)nV4Ty-48-DZc02E-lRFH{g7xA5W5(eQ4w8%4ep= zlf%wE48GY`E{Ba3{5GN8gh=lY(o9 zX{U+f20M6$%{y1pmL6+1=l9Jm9-poZ9UI%UxwNrb87*UzAn$&em8}F&*<^|))C-k? zN@66k1i~u1_$lt}(to@}-n~)T^3XSa2eyRM8moBhiPr|Vms{!3!^_M3sQD!LS~${_0ri_nO)3_%mX`RTYM-_7A8W+a_AyBAz;CoAjF011`+@5c2dD1B-QG0 zGKDiu?pj=S*G)~duRC(QJ~KBHzsP=k{cCQpvELq8&Y_n zCu3rP|x(4Eb+1q~^KAG285VY|DX1+1N z58`T{04E2_j~_iUKb0%4Y#1IH9w`+!RA9&W+F-kdIRkYU?t-afz{?2%^-&mAp?E4K zIU;AOgGtUp{byInqI)EP{!3AJ3HMJ7ZQhc!M>i~eYkF>?Q?D)I>q5LeGM90>Gbd?Ml( z+&%Y{>NkAF)gFB?brn4AuJAO#JSTc=F#kxL_L0K_6!YC*(S2kXI5v3D2gvT*ozY59 zu?!M|#y=W=12zD=(rsLMW^iX~5xyLxgyJEw{d=j_`G`_B67kpawEXN^C{v!914r2* zjeL~r%DDcKQYk5qY;Xq(Rd@BojQhtY_qFdja-`mBVrP-RL+8nVd=5#YO&Se2Cj&I< zTF#G+eT-|;KwhQO1VHlRI~+{}r0`g5dWPi~rW5p`{%^kq&W;)g128Kr!}M`~7A{C; z;_|D)AaWu=!IR19-tptJlde$PSRLFnlFyHhU~gO*TYY#Fg!kpSC_s&5 z3I@3JTvs=tSWp+DTR;;BY91B`zy9BNJ&TV+QsV*5$G!0Sk41*_>XF*e<*0C|I|l~_ z+z4J99LB`p?qlQA_~!6Dlnx(#rkoV8j=@THpynASPA8heo@#X?bp63|W&&{2%{M3S zf8YDE%HNZwqucTP9~byrZujnu^&7tGYWLsc@KIogoUqfl(XAYqnjAmUPHP(r#m%Dw)zP8hQCG%6IXn;z zpZDbLE_H)Bq@ntuZaU}mpVysIyg@JWbVbx}yU|EX_~hVlJ~x231uiJyv#~qJC*}}E z-Q@=I`2vn^mhmSkZU=@><$BxrRJ><2?wr{VaKVlpoXl_;%w6^G|774r&b=Fi54uB# zw%2d}wp;w}?XEsQl{(Dw_>mhk-ehLe*hulig+1TGQIi>symB_QA_ma`jT)i|BGERg zY#j8unhClLUID(}Y5XpR(mOu%ys> z2bZow5J~&4Ujyev4V zcI)!Xf8i&}LziA&t>Vi>og|%^Y{KR3R8)R)$TqE}*%l>9QSHqqu)h|=Ux{6`732{2egyz`!|pxrc~A2CkA1A;4&#LmxX;{i&rhP)|68}T{Py~HzU7u~`iiR`d=lr} z7L!~VhX94uaIo5XxP|@Vl-*Oyh$7ayjpyf`w_;#K8KaTG8M7x4VG-Z}ZCSyGjKX|9 zuMPUZN@2(sF2o@cL6S+O!3JUs2$7cYd7McRK~5h>=&zB<&4)ESEEnJ-BbW$OaSZax z;D~!582>N8_}6O7?BG-?&1q54b+@m96e}8 zL#~3Og%jNQcAD7w#@xgA2CN{^Gt2-w2cph${l{zRs!>)FE{pn@nvoHCzE#oT5zFOH zJ1M7WG3RpIkIyg79_h3XU?1fQ*!W=~JFyYfLOmtVI+q9P+ki;q4*v4{ZguV%?FINm z`WKOaGlHJgGXnPc+ittfJ@Mp|$yfg2AFRSA)AaHY90`c7{QkzBx0RNz{-Rsi{Xh$! z1Df_A+rovW=zH;*3$`%&Cet-39zzo2a&^3S#A)s zf$8#~yB*IBKX-V%dFA7e*PAOfTI)8X&|2#m04=#JysW-<{c$D`ul$Yn#9m#7!P1wJb zCSqARUUlQ-9PXIL@v#GAn~F<=!;AMEKeivy)Ma_k2W)kH_lDIj#u)uD`MPpv^#p*& z0)F5FA8=p6YXNkhP1DjFocjLc#aJ)3LS{)=0>onHfLxctxvzX?n>^k?4zXdk_$ zq`3}lV*nijkbLGygEtmJ-+dTmjNn5Qnf#B1LK;5}U=*CujL!lg4-i6rL9lUjCHhDc zz>IAA5QJEiza9#sRLaQG8jZIG_96t0|3I;j%nuB@Z(*$ek3+{B*YDk1@6=al{B0=! zDTveX%XrK1)2P$P%h1dCizY~ZEeB{RfX1H_3;EdaQ(48zE30({_}RRdw1 zpK#3_7xIkM_z`4WHm;yE_~jwf1E4R@I5#zc_kQuRuj_2y+T5^tOL-Wl4W+du*J)v2 z0e1-?0W!Bc71Ln|n2I5!BEvtN=^A8~X&g^Avhlo-`p@70ScyV;z3%iy_baVda@Gu; zRZ<7LCHd%hAQ{=P(G^F>lF58|aqq-&-th3oh#Lg**dU<#Rh8G%vC&*oz!x`tL!)1Ceaq&1 zeo*kf-J0KE=q%PS)>!DymIogobg7m?c?UB1vgWm-Wg#+94ia!^`I1;Fi^$|4fiIKd zviV9zFr-_i)pTD_%f;mI=s!$|(h3A~SRQmmcTcV3K7Vwwam$lWt>CLaGRjS?5b)SP z8GlUxbT_Yw01drx4hnjvAs^|QK~5T&virckCtuWYTmP@0{>eA}!iH@> zv!UI|CzD5WjTY2Ep@?n6I6@U#1fDDB$mlH5e^yE1Icw0ss1(g#SU*;2nXV0!BMb9& z2`IwG%5rC5X*Tz&%E$%3xoy+Wtc-6h+&(eB3rQz&uuMK|5TGujr%c||u-@sU(|pLs zg_0Pr=r1@tD^~z$ynpMrek*y`yWVAu$y&rYz^|<0&Od2)-rK(SuB3L;S6%(7CtO-C z;(J^8jz-7c|D*M_O2;qlA)78EsfD6eF%lSknqb~7yqX!3Rue2iG#y~rGE#o(kv6bH zYKsffS4+%k2YhM|5o94H(B|_$P6A(pMMi?n^NKw;euQcg;GDKW9<) ztzV>|@uuOX@ux8tq>-nAm%;DF$)^beCj*otuR)>#!oi^d!b19j0_nj$rT^Qnfqo5~ zZVjAlEKwWSi|)ANMl@FAgQb%G3eswuK!G)l~g%{!m@-6NwsTX*z~3G z`B?tK2yAILqx-1Koaw(6V@-<)tHE=X2 z1i{*O{Tk@kz%#6Y-toh5ug{DVB6yep$08k823&h?er|5(?EK6{Tel}$hes}{!ffWS zT^tB7uxY+jc zM9IZ49XnNkBC)p+*AVdujNtiwB=NPp7j2n@YywVxpiJeFZu)K-#*oLS39}H=Y!53N z7M}og1@QX>1p)i zRR9@%!b}MP*8l-(IAP!QYoK2Pr&j}BHJr%HaYYwHjWt4zL0cMyVZ+xy3~kRZ%+KC2 zGe33dwjG77BO{ma^P$PgGH;91l&=l&ctJiIpzugHnLb(v`p?RNvY~wT@3kjO>%E1E znuhH1Dc;nm@mdmGJnr`Kz9f87tyFQ2$|lzt9&LPYsW!E^xUh`X6uv58A6fxa9kYJv zRL`Q5Mx0Jih4a)G==ZFf0DR;lA4#so20$7Axioz_9s_(hX|{jC-F;`Wg2wG?aX_qft!H^UBfBncc`x7RM-Ixhcpyv*+~g>=^7Wn9Qz?UKEY32tL@H~_ zWq;oJm$B^sI85-Bxby!4p8r2GF$qI$&j4wpxdOn+fDC_Z+ z<>Lte2SL2-zn0-wl?Wn9-}P&tUjxsw27(q?m0DvDkBdct^i!xx&r=8jRqH z9J-GWsd+=31$$^wvVbZ-1jQ@3ikW#RU%{Axa&TpS#Nb0%7^{fJc}Up(lVlTt&*2fk zBNKcC(24KZH3^`Bmyu`3)+9g^0GyfW=oQvvfN3}xpd3yrw93GVfM&&94bTA5Akmcy zf~D{JHPEkt=THM0ON6oKnA3_J$0WzU#;V5uG7>DoFJi|a$2NJE#}Dm)^snx^=WDkt zw{AVY?c$Exaj`3uN<32!?-N37&^cX&iBxdRJkx2!*L2idA)*(q;-}7&-V=-&D5p#J zx?5pE@H3B)kFtxUSRNK}68(>BP4k5uKA_?X3p4Jrw4HzJ_HF;_4O@3y0y%gJ?MjtG z0dH42EK1vF9Qi3nqXTlk1>eA<-J*IHWC5c>BJ={evtj~3)opF#b3Y+g|dFDwUG})VN=1U)^<#%lB!Z>Lq|?Tp7W9 z8TOp)|Ky@K7t&_oIMz=-vfPy4&#AVt7|P9;FEyLv)R2=oX*hMsY~j{vAlC`U$L zhM$UuUUd{hkh}H9K;QLipkD*exdxg@E=<>+ zICAi*|8(znZ@HtL+&Q)V5?8<^V4zsc{*zv$E=0Li4|Wl8 zC}_{q*8jHW0lF2{VFv|r>eIj^U<4KP(#;zO-gw!iTan2qe0~9EE(2EZ!}FPG{OM)< z;|T!mExoU04~2t#<{b;Z?i~*T+V#U9CLj6j-)3iaw=6GJUREsr8Vdg*_sAnV8aG|< zmhnZPPN(Ja164Z(5QY(5v|G1q`4BeyiJp?hlS@6vr|`e(Et0Z|$7K5{XjfJ?Br=Ig z!*WZG@*qSW05a*m%vru-Wa8j>4NPNc!}YO8@%?|k0%$w``3L~d|D#6$GW;_7H0Cn) zgf#fNyVoiJq2e?VU^>b;mGS2#OX-)zE)UtLEKBV zadv)=CyDa)!Oqg$?9>Cb#>^ELTv*yRJaX|6^iFPNS&s&&K`pniAAs42l4TiZtOABq zrVpRB{-Y2G$G?d)4a(h67DmW$#>P( z>Pg-N(V*C;8-Y^)X$6#pVwf=Y2wIqsS#%3a${BKJ#ROn#YRcVk-XLC?CV>%eBIT){dL!zp6K99&^QPPJ6C--q&3ab0AsJnsyT$&s-UvBSY$ViPinv5 zVDDiIDIDaIA`&5aNF(a$SpkgX^YQrw7M~y+In2vTK!g=32s3d^!&v(@0T`@y>@T3b z|IgR{xbxp{{`1fOk%AqRhMNXlck}UGer)vhC?K8yFpVY;GX9)YP_FJQVxzB)j%afX z_g%jR`Ze&v)Ijg})A)=bOJ;_O+69Jz&$t^4lM}N$XBTEJzu>}T$H>T~gZMNtP7+M` zx?mE$F6i|gl^OLDBvDU!jL;n9B0owe3@kpuGt+-2gxeCc+)OI7^SJ|>&i46QUKSb3 z#=LzvDh~_HMGb(Ez_Wqs%Wa7|je1&f_||$MKU8U_n~%*cv=2Axyg{l#7*1euI8=c; z@z4IhPl6cs0<1L|U@oi&dbyCff@c=4`^muPKmU36cYpVHS*?tx>7~Qi4Ct1Yex-Hy z9l50&uXQU=Jc4I7*u`1J)(ti@s@L~8G$Z>5{#fG-_$bd}1W*DGld>`JOU^9Bygi*5 zoW&Xv*==J%*ko8vOtac~`9ZSJgxQDu$ZNPI$_ijIeV1WD`Dg-3Z6E;G5x_@sWjhFn z@Bc@y0CLGMTlNF4$$;+iY4EiYz)65`O%%jWs7V0jaUvkkj?U_hXS@hzj&Xh0uYrCI zyf8Je*7%EQ#1-bwSTxWh}dhV{7`N@~=xUje#69Vix$~n9>(80U& z*g%J8k#>weq|lZIi*Ku(Js133^&iARJcUw{scn?k6Fi+4;x#8Uq}~4;=X2Bl6r_xC z@}ettTFF4WjrIPd+D?kqJ#!1=i=Fla%9Rck3WWxjrM*6sP84K43kRCjJLxZo<4W?n zc9&m%xiv5g`S0HL`r<}x0z{$T-g$CwzIOY!TE;crHdB$%{JmY1FJQLf33WSAW0=jDZRST|Ogj5}C-UtY?w z6y!taqv3}`@9w1h2IwGO?^(ddf9~lN+zrzUjlK5#f7LU3O#_eP6)osgi(^rZCzO*RuVX#T(wQ~}Cv-0KEtD^3H`p9lZ)1*x1C%bP zl-(OHx^TlQFS>XWgm4c)(!e)sV4wJOmU{!RWzD?y2JnWPo_3eT^hNFB3M1;wxOKY% z@Q!!9!@cfxuXBI;r+=E&#EtuoympWu1Dcup+19PM;2@wITyx@hnyXYCzXli_dmh?~ zZ3fV-ToSp1j?G9`-|9p>&Th*H^JsiZAYVqeR0tZR4EA-(1c{x+o^1sgh&8q#!Ne$O zfIbaN;k%YkZxTH_vtXRbAh!`9*k+*}$L|31%YXd%4;}&V2w)!TWkwoFIk0Uo1M&_& zzUwEhWq%rf;o>1=8chHwhlXFqp9(}102VLy2%77;bdme8UjzLbID<7{dgvtiX^i%c zUkgK5+Qc4{fILZF`lVc`6BT=45xNau^?|tuk-OvBr&*iVa`f973hj#DY zuzl;+-#~#s(Ajza(8|}YclA9FwbByKz$;hy3LqzGq2hcWG=s^euuj8jHOK1oohCG> z@i7;KiCdVGLbH&Kw5XL3G)BrIpAWMeX6ZvwJcs=brgo^lM-p)c{qAP~$d+&@>p|&_Cru(KT_509c!oljBq4Num9U z;gJ_@E|xd&5oEi$g0qHj!~j(r9tl`JNZ0G0t^PAPK^$ZlX1~&(WbhH^IP2BdU$zYOfE;U+}ho+}%P?or9`p6%C;``2py#V+G^ zyj`MmpGg1WL}G|LLx5`&>&|icrHzL!-`ll|HD>P8SHAL%SYY|rZhT^UedqVw%ASYN z7MPh04&jvm&IatY6|n%tHr$qe5rrv}k-E`eM%|n&L=j+q6=aLSZ@41#Qp964R3Ws~7C5+6`QZd0HmTp%v;I2A0)x2fjzIyl+ zpsn#C^{Vwf2-M6#)?P540gx6i0cduinE)Z>%X2oMivYR`XSnbBHPEkt^;H8JuY~lv zRn?g07}v5NA(pt)mE~q*8FwJm2XwVNzW?1r5A1sI$dUOa*Bad5DnnyME_(BTT?nm$^7wLjPU%{sou>XLFDC@3IJ{WdNb|J?cX6xc z-Z)Tv`CCWFUJc1(@T^z7Opv`Z$Y%qrqWIZB{9GWuIIx{Lw=S0iuDId~_h*0hXYQUm z@3an!0|73^+n685$1UHV-g&2e9K9$$wmM6<* z@`F6$NS*yz&;+qyfeA$FSqmA1mtmA34rFtlMyb3RV|jRmSe|VUa3Q2R=xWvB{6kB% zBTJ3?G?VbPEo8_lkw?&QPPph8rjMP%%<6e}>v956tJT~SPds54|NpGa6@IZ${xux6 z@Y`ewLAX|=I)&g=?>dZkGOPA%a>Ppki^ai%GZnf<;MJ`z!;A z7ZP-}l_V>hh~o3YEaZQz++HRs0X0FL?+b(tg05UD<|-qju30GNCKnbOk1i}w_tudg zbtj!xSXh_6lL6A`=?Jq6GRpJ(v#uTiaCrqE21stc`R44hKVBYr33}7p+|<-d8u#7p zmL9x6ZMNzzSE*tjKpsi_QV*H~mB$HJclk*9CZ#AU*9dJxxdK5q$pLx>^lbT3T{%c=Ma{|LyPp z-nzhdckddzZ0ol7p>}??dEdPomTtJl)%NV}bc*<91K&?!cR-Z^`l>_EAf_;DbCvUK z77e;j>{Bz5IRd3yP0Og@W$`QwSw2sNcqSYx;bi_y4TGyeL;q^Qh$Ml&(JB1*c z^%Tk=t>p80d|8;rtNzH$^mt=$+iRcvBgVEL{zs9V9pO7L}~m(a&7}`MH7@ zphjbB@?W|+L&8MvplP8V%8FQR@tQ+??fAcr)p*?%D3V6jUU-f2G;CtPXV=rnx@O|{Q-44&b zlLXsO>|_di9fLJyNzh-sY0d=j%0kaE9<$Y;0rv8+zh<4vIuqEe%ahX+d>RY0ZwBiQ zlq7_WE2IU*h`wz6^{I_a9?$0oN=W0&h+l>Qm;#?az-iREWD1kSZ_F&XFYPBGX6B=GX6B~GWwhZ=rI6s#c7p5s{x!m#KvD8^<>6Bx*(+d(K^-uni=ivhq{GH z3!b?Nk0I%OcMjCRO*h@-ctY57bnF{)aX&dLaM)Ruv-b{>*Q7Y%y3S_`HICzPPMqUE zUJanWp^m8GeSl>g%u1YTXRh7({o6k`KK(C`k8FB;<)X`7VdG|(>)_+%{K`;JbOf0W z?3VmQ{bxdvjFN5b9e_dng!Itej5HN&xaen8|7Yqxb$kb)h4Ks*bM8fh1MVj`ja~AR z4VzwyLT=`v0f^=oh4fV+eON%71UZr7jW|8qS#1r}9Bb=&bL(aTz;l7=-v91*v-9z* zK$oDVe$F+TZ{}Blnh)IXItz1nAp>t@;FExK>=%S#I!KdjVbaV+RcAcjY+K(6X~5=_ z(0Y4e-LyUpA}EJ|OrCL7UXq<<9{8C^X#$VQu^c?JO(H{%mJRSwAoK*>{SV+})WuxE z-L<&vt~zw6_5ZW?CSZ0Q)wyV$u}`1V^PqViY{|y5Y-1abU~Fv6V1t8W9KsYJxe0?q zcwBgVH!)w52ls{Vy?lgwdG~(d%W!W7k`M@(Axr^;@oagLY}u0BlDb=J^*r~P_xt}< zwf3oV)NN~OsWnvhK2^19)wI^CRjX?6U3+`~VV$t^7=$_~^%($N`TLWM8U zjZ6yatL*EzQ2LyR{Ofq8Pg<$Zu<8R@a3G#9;4J~@o-DpoP8jPQ`KKTM@RwgdH1N%? zw#7U1t2bIBfGVt5kjWc3)@f^Pjn(?kE}@)02ZHKrG>7_AbST>9e3mC+g$ur`Mm((x z5y8>&;8)794Y6vSh^_$mHV*?99>!^LunY^9Z!6=J1iYd>6Ew_>o6F+mm2YWpxd6%h zst_mmH0Xu%ZRE3pwFUs+5+HAtzphxV6)BZgN#tbyuyG5*J^AF5?6~Cy0ExR54iV(3oB{->t6hDT zZA&1kO|(mXHc<*gf>g|+90WOB#1+R%ZC&)eY>aAqYyl#b4v76V>~5s7yA-X@n4P7V z`OeTl>A^#Xa(W675Q{jGf&-8fI4@4-vpoZ#D}DNEJZK)S_-9-7vlqNn88Cd@j=WL_ zy0Xkyb)S0fxx9JqIpRgGTC^z9k5@!{#>RqTkzYTQwn>^7W+j^DC>`Pv_q;oUDA3$Y z-6_IZ5uUl)Z{>?T*Nd37VTI9Oh)!j;1jSbP>l}9T9>JUDxOaR>Lw&qIUnn2WbFC?k zz8_{@jT50ZPS~qC=GS~$mX1{#Oms|_3uobqA=2K^m>8Oz;1PLKfBCI%KGOW&_a%R` zv$bW_;uXv53I&s$953NBL^wGBQy_9ur&iQ~)3H)>Mc;-xn>D&_i7p0SMK7}%bhbPx z+ydOM1oclQRrp8d)?1sLyE#knU>eAt*$Us$7_`lkQHtF_227%x6FQ*~qQ8 z-pbC3dm#wgK$#oN#MI^GXP+^7>;x1>2SKhRUbz5`FrT=UrJbLVOI8gkAEce-l6baM z0yx!EASlqpVFoKS8n(ECBPbGg(&;dnBdkdRkZwR+Cgxy}_08sNoq{7znI4G~g&~03 z0Fej`f!%lp;NONvO5ZtnIG2S3wp!<$#5t+^w*ffe>rMby{JI06y9BxmpvD7z3Lr0* zOCj_xAsS%n=IWHDAK`n30LE)&m>&#+hIV6K18%NHq1+lH#meYZf0r@4wnQS`uCU;- z{(d_+5{XzN48my?%EP;DmXOc{@KOS6Sn=qecV`#{C>X>0_q8;xSaDS>8oL6_<*JIZ z&k4#7Kll)kP`JQ&39Ao0af~xS!Jw0f4W8Ctw1+b*9~_HefbZWK1lz8QM4okxis7l> zIL@EbaY-<{z&L%q5EREa9lNJt0UX5-@tMz#H=BWBIxWj5TV!N}|~*1Fgvaa$md&kjOA!X9uR7m%U=2=$*=q#)X=d_8NMfJSH@JO26p zptuljW45)jpbK*%Kx|Rd@KJ|kcADCSEw6<3T}YYL1r8MNOI3cdc8u z>3{C;$p#an2T)28Z&qYrL{aCe{HiXeEVGze9uua;v!@zH@Z`ADZUFG$>6>r5Df;=( ze_kxk4`KUcjWKUTZ*K~^_azEXK4yvsy2=!u2)<+?Ge1}&mL<)(aJ$gTLMSxC>I#uW zUN8YUFr%&viUcT2CKFi6V&wyIg;|*+g36spjUZsYMoX~E%yA>vE9$P?DW zQgLqyXKbX<)nvNCbSE3kcSfd4|Gd8^H!?P=lQo4#CvaW;>jbZpKPP_Q0H9&OIE@8f z6hOUvAyfgR&z5WJ)d%SKoKF6$(M=e57eTS#2($N%W_soVGccGi*(~Y^N{K@8z^2i$ zog@GFFHb+S^ZBRV@Td3hLXB*rS+rMUVt%^^+8xhsdFYnc{m1s7JhJP7reyyQ$7k4KOfIrgWJftZo%oBq&oy2Z2k1xb zSU&S<9jupOIyJgNV&kYl94QzNa>b&wp*%X&_sI6`&#u_IbxU1SLqn=Q6OBxb<0fDX zpW8`bFHk=)fYP8aef`ItSiLTFp%J2#eU(b3jk(_L=2PLGcKy!=v*DNu(6$IB_y8xk zL{??e^|!}TTSi7k;{P-;$`0)>39j4{pzbBTY8PLmFE8Z*3s)D?TmdJ;KkWtp1*mhy z3T}b00> z9IwN;2(!Kz1Y5yh*m>sGU|?W{k=Vt{a9_ZW-_TZ>;xQ|n9#w(wkuWHZpPIyu4(FP+IjyBpa6`;c%&3G zm0sSP%su)b9t_59B1|dK48CX!eLz={usJ()6ex4%o!Fl?=34an2D5W#tn|=> zCV!x-P>Mz3*!~lNv4R6ka9)=4BvI%*TB&5Xv{0T1M?~U^BOp5oSBi52#{3SCd87tc zhQI;SJkqwXEjFNe1jo-O$%KZv!TG>6;5J7-nlir{oi_ituer8dRQ^El z(o31#uYPWFPdsXZ-X84X+G-<-WIayYz(#LFL#%W0doM~gTzufYA9!KcBM)!8b@z)u zKv|lHoEbhfl#Fx+9faS1Q1k<3mns!kT2DKJ#wYLYa^OvPI;`u~Eze&Bx@ zqt61M(P*f&KZ-}!5Wp>vwrDbPNoPm$Dw9~YCvIpAsqHOGrCs3g%yW`-7i%cXP7lMPX5+Kn(#-@)RgF0(c96VfC4=ILyOK zcLTIc3Y!WZ8>1J3M-YXuV{#bps<6!7Up?4}8@acFGIx~s?9SwW@EtSt@82=Gz8)$E z6HT)Bs6GZt@Ev2k8kiUxZcMc=d3{?V`ua<+y84<2uDCMs_OJil_kqYh)~#u2$@ET6 z7P5r`>EriB2M-ycgNOcH&N5=I)bsGuN&#reNRmo5iW{vskqsZOg{WZll}N~w*{*TQ zL-KqsM;slTuY@;OeuevWok*FQm$w2L#yxWk8QfPcmt%Mj&y@OevO(B@G`?O&gMe~Q zc~_ZdKX|G9BPcRYU!AsB<45aj`#5%32gft(@yjDz8b4!q1=z;2$l^=gl7u zdI*O27&5|hr zj!hEKj1EVl+-8t^U=mAq964=LI7=gq?;yV%Nto{skDH$yKAbmY9E%8{z~ccWz6pSO z80V!Ey6yC&yv?O9j}pU3=X!m~c0kp^=M9+n+Gg zzxZ)EyKfI}o+YA@blL<|2z1~?P%0OLndx%S*PV(^Pn#4TEXp*sUb;2Y@X>#|?~|!} zzVX2KOz)n-J;TH73%;NbscWvUFAvPXa;hjP_KSU_W8dg%`>1f6dj5AoQh)-?JyTBn zk%mSSYi*+r2qHM56(eJ=HrMi2N39QMSVye-etETdG_E*)S%lTbXTzVZ9&HEG%0;XQ zq6O^zjTcK({e>bYR2l%>3E&{1%yV3^9Qx{5hF6Y&Yulr^$Kq?5^f{(9}I%^Xw0>y ze{gmAsqLot;tO~<4s#yP1Bi0QS40M!tC181SA2?St(y(za3o37)n}T9r4@+JQL&;O zf$z!}xRybf?G}_B`1$ed^;)?|kU-ADeId9Uqh` zLGc(&{&9TO3{Or6g+fX8h^d@d9xwJ)eTM1SM_XUTmxS{_3yT5}TrvLT-al9i4ugAO zA2)s&CnI&m2so{9jfOoTz7KS91*oC&8Npo^5DMBpN300@L`e9ecmf+4229yW;Z96>W=euAiDp1fv5c zU(A;_P>7!X+JJ z0eBNYD8+2w`Qo3{L&9$X;Kp*-UXy#~NmJ(dnzfvFbxHOx~l|vvFFE$f+h>0#!mx>fK zE#}ceH2CMf!Tk2a{km!|LTOMa7}p7%D}8^`*DZhF0MOk4=FzfLxF}S-C}g~RL1NgC zBYOOfM?R|q7vs1&R$uJyGP##uGUchs01tTv_|}%tLu@>fgR~)G!I4NDpGL+pX}QU< zV5XYyA4xl*aVfQN99nFlLUaCmX? zNJEzciWhP9B9C~{`C$t=|GOY40AaPfQBK)bxtJSDuBD#v){I4m?#88Ky9H9*n4f9h z#gYY2VTcRN6(zWWp@8cAEYjw1`B)B}^(8FjDO~W82d&{OKT!@6W2F)&|5jW)Frg8b z9yG(rgR4i%IOW@yacvNNKaA*cJ0&fBUaCLXRJ~-U5g*aX;kMi~8xEJ-`OBZb@S_7g zj}64?hDr_1xRZnJ&O)B~={VrUz!O?XdjYA`MxKOpWCq2v9dop00-R<;u!@&btVMA2 z5YL7|e+iHe-ev1Sio#qg;8{obuD3>CHYR))z_pF(wk%h1z8qjOiwv-^2$2IQl7R0h39ztw&w2`VnkFQlo!HAH?@oW?}H0JhunD1)=J?9sET zN}0@An}_!$fMm0>42Q4ntK?wrFeW1JAP{}FiuJ(WiC{S6(_63(cb6jOTlg~2zrWm- zGsOZ&7DpLh2Vi)%tpK$Ee4kS=tpVK%@T~#gBGAzsj!NXI?mGY{>iGJHI`B8ZH%3dj zi4l_>8^V2mEPD9Lhjn~nNLm12XhSfp1!o|@!@D=d(cx&M{E|sePHx;#-?Xu#IX$)L zwp+eEeW3Rrw*P9|4q&n0v6cqxHI&Q6{^@DbjZfj=9c!T{Eg{lh`_H;~X+y)h9UR_y zce*J+rg4bXxC(?EJ<{puwJ93YF>A#PWt`ga4`~xU<2MIX9btovt-03MM7Eeo*@|f4w!8%bi%V7JYjfioybG8G3lYax=nHk0tBtIJ% zHviGnQ^LWM%6OOravn8>gBOK^6Pg+WxrlfI^@5OKoSOUtAn=|z(H7osQE`33+g zB?*dU(4&kgnG~imL_(8htXU|>6r~q@kP3zZKfaZY;_1OsVRX1u#P&e6d$(zs9Lj8I zZ+^$0yy@nk>15KKU?N)sYE`QOWxc#q9;F?KpLYw0 z0uW+|3eJR}v{szu6-S$lEhbQ2;7N)bhmnD34<3`jJh2_D_U2Klw)4fe&@qG>CTdp zB(#_66i!%dIiY z?|8`UR*zabAx?g2sq?v~V} z_0&zu$5-3JRGyLqN5~6-$Ky`<4gj`zO=DA2*nz+J_kVv4r1!06Y!p+IIB;I;k!)F)<-jVyWm<1j5GYT=oR{Dg-JP z;yaQ^i^x|C7G!3%aYzDAQjvYNLLRox)PzaQOq!;;WO_>`bLXF}U9slHJMZfH>64E? z@%KI54<@v|xKkU($hL`s_bxLdP&2eWq)iu=DOTQ2>KNR#G+9Ti!Sh z$)GwD#y|BC^$t739~mK5?=YxBM`4|$0Z=aMJpsxn^@DDkxt@y*Q;sRu#9^35Kv+7$ z^Wn69`Z|7CkJcN>;n7BXSRjRab!^+#UuG`YWPW@3lIXf6`74rmhd4hv90~9Z zLY^SR-s1=Pp%$bRQUf9CT?sM@hqQ&S|GDK5;A{)D7do%8E^anN6J~2&bj3rF=!Gxa z(=84ml?DKB1&~I%cq0$V=U3vXlnfmD$L)0GbKC_SZN@+PqdyYVFMs*V=8-3!2pbJk z_R46fd>sx2i0AQX!0garQ{toIl|uo9`TS8S0P|56g#yKJIN^`~HMAh4a!DTISWF33 z!cq!LbLryS`WWOqg)|3Md%)t7(bm=GC)BnT7_6Uy3|Yrsc#y&k?-)M1{Q?dI_}0i| zVcXy^SMV}v<23+|e};9nuMYy$8UQ-+)1PbWpF%`|;vnTk+WQxx^W!EbX`@(&4hi*y z4k5)f)dDQ77`FemnWQ$GOHz_eNTXqx#6!2a8B@Y;K)UP2mW`tWuYW^Z%LhJm?e!n} z$W3p$9{9Ah`JL0`s+N|f`Xmk?ICAAg16X$hboErbg0k%f;(2$)6SA1 z)CrM{+$wod4CR~kDL2-I0Yo({rPPk!lR5rvS*Xvp!?lSGkS1t57!#a4JQ@JGAmA+k zT{Y@M0sbxkCyH7*w&hp)tL3Y2Q;zRf2BXW$u<8}{scWcnsKaQmWb2|)`mB58um1XL z5B=)Uz(b>n`l$dw}*HHjh^@;K0axC95WIG7ovApmazq3BgSY6c}a~1cntZ!0<;h zRbnm=ki|LArK1E%XPydzz!)b8zD05AUMZTzA%^(ugqBNfChGuzQg|w`9`D2r#!_b6 zM6UF+zW#hEm*s%rAkr@bF;0U(jRG|cbj7c}8WF_j#X-o6gOZmHQf;{UNSa@VcLc)< z&!LwCSuV^>7YhdunD~LcrhR(MY;JA3 z?EPCWdH3(V``#N-1(oOYfzi>KnS9>JyM%Rhw7yk=suHaoWd2~&cB}7Ne%_lW3LHUa z6@}UA6S)Y5#mBI6qY#xXMXfH=%9ax}o5jhT40gDs1VLy)Ou{joc%A9|Hn3dvL*PEbuZz}KI6Ujce z-Q@cZN?W2lMZ$K={c1lYiXRIGZ(JCj9d9;4N^waN=8q(W24x5qIC0ggbVbl}%(EyC z&PZ673)>_qLF!?gdA+hF4vCUu0dY%YlFtAP4x4{F&|MxF9o9*khi@`mJL&to0lEXg zrMB(>&=~Ly0WHrr05~X}bc?THfak~Y){i<{`4Ls3yQC9b$V)~D7C4yV!XZ8Fst^y< z7@V_;mjUWyrDDZ9O0+aG`Fp@G5g5411t3-D|}tPzJj6!1Pc6gmqM>eP;ZrJ*ES`Yn9@kIvAc zp#?r25XUP5_;}z&3DbO4ecgpfS%nLCh6CK^ta{EvjRAk5;_D>UODz3_92MUwaUcEY zN6lwG^BMA2+@T;?18Ke19PC?H+Ww@;y|^>Tm-7*W1sZ$j#DIG~ylF2G`@=mTZqLZv zK%ueQgmNF5}3NS0HAW95y@3xkr0zQ=-XPXuMxnR8<&Wv)TJPn$!1Cpi>TSc z!fYZZe;f!9Dc~7^ofsb9J#@JIL~pOI+BrD*41iAloYZyV_n-P_ShxSx*U6uGSsn)- z%hQW3vU4y3r^@*T02*S6P+hsDolusAYBY?M1nr4_7-L*gn@esg7a6nJN^bFud#V4sRI>tn2@L z^676kUw(zTxw-k*I|yEyyp3m>3(*2pbJIualI{LSLi_8Q>q2 zqrl9&Td`t=c_Tgzs1^PBTi%+)4X!KEgV*p-fFfQ4EFL~o#y#EuhsHr)xii&q_gG*vABVt5=(4#?;NzXk-KlQ-iW;1mX3?W?bozd!No z^)Y5@wkd($Uh82uzrp|560_KrA_EfUn;` zao`EuaskhjL|=Z^qAvinK87IM zEWN7e5sBi50~l*!9E>ba|IfDS*VWLDtEd@2^x#Yx!=_I3T<&wly+ z7faEH^X+&$pb2k1@=a)delUtxhA^_B3xq!I2Sw1Ge*OOk|K-lt8snY?aB?R+73SGC z*3JdebpCKoz=e~{OaUh*9{si9>L<>pdTGt- zBk9;(I6)tK)}zm{eED*-V$GVcuHX3H11r(HYa)|VYl|=jvfVGkQo@D_-WQioX>n4; zMIFFef}aeI6#B+#4A@mDEI|$!y%nGa0VjGj3})N$H=nrA%-ASeZXB2-_d&P&Mp<|MO5E!z`%G9YI|6V)2pvt$1k!z~L1Wh9R zKsF9TjAC6x<*zG$-vFRI`Ua~npDai!VBi!xWdVKFLu6rbqEN`kBGLTPrY80yVjkJn z_k7R6y<^c>uAFJa_aN{Y<#H*CTYa4I`D_42wKbh8eW)J)3SY?l=RCmv;0C6gC7c1* zmPd+aQ!H3@VJxu`eQ3eU0^}d*q7y%PKASG``C1!BmSc0QbY9)EWy=gd4zRDMCmfe} z@ox)Sex2F7x25>P4wD<^8v!wV8Hi7aR#xY180JqnAs~q;jxd2cpKy!k5a{`7F5Sng zgk9ML)ZkUs;mVV8EoxPJY-Xvpwk=}5@)1YY^!!ZT{BU5n{P^L1Ox*G<;M!*ZIBW9K zTLHQgpg!Sh4EQ?%G$8cifaBov2cw1oJ~b|z<;O967m7d#^bwS=7G`lRUtgX7u4Gz{ z{0v(pz^+mbZx7@K4w_is0kdeNzwO2#|Bk=E{LFNV?-pvOEAjs6AvpSI(q*yueP{5Ti&7}*|9Jear`5FJ( zp3v7evR&FtKddn4b3+ubmf=xyIY~}sk`n|kl}&#qK)Qr9^<7Do>J%_fJ~^aZqF*)n zBQ6UZ^d~=+&r`ntb-fIE z%((9m57Ph-!wyffOL+eI&z@jb!~5#^q#!yI%uJP=vQy@QbbaI2rAwE?j^l&NPdC(o9ZmEWWVQ6n8yug6ZiX zl1XFk_w5ne7b^!9qkvF>xvr|5%+_;FlLmkb6avD;7a)HsWiuA$v0Njl0+U$fM^V%l z-0%khsYqCE>QeP`7QnWlaq~lb4ltLU*2%i|HUKAefAZH`06OvelRt5F2SCfyfyZX? zI&IE>02B?WnC@PS{00i`Lq^(wDnW{YtCKx_o$&ohfO5)gdLejPo!>o<4?4C@^go}$ znc&C8?XE`or_Vn1Z1eJE|8(CqSDOp!>TXG9XJVznei}Yv^l=w}`ISd3Nch2khT*%Y z!1SkzZz$z-@?RK@M$)j!74en0M4egR(r7jou|7Q58-sS?WFO$RFpd|Ng&~ar(uq1q zbv*g5dWd`%+BhHHu{(dpJ@(v3k>id#?x^BThcTOA5?mJa^|j>o>@rz?Hx@*R(omq{ zM%XHI_Kmwh%+7G=q&)e-y%;T=*#zH1V%@K7XVM7FprU zOyMN5#dLVg%>4Xg2tSl~j@ky?-wN=0`it1f`{meFVgJZ58A`?yg-^~h&Z~CopA$SU z-4$Ti-}cu@pXKnPaOkAuT3<~(q@Oa!!@<>wCSZ%I9qCx*gs=jU=7WrcRArPr@-qwn zDL*Ph^2R`_K3a+;%K6EOQmJ>pNgmi^7EKPBOWT`n{P;Cj|N6V`zV}L0z?J_@*T_hI zVrC|SR|iv#_SHe%di9krJH?Al@WY6Tlcs6pynm7?FgsO6I#|O(9RIaFS6TM-#_YXf ze{7#v1ZAvt!mpJ(mNRErEaVh99jMZL)Jb1;lKNcT7n)Nk)mPKs{J{^N`(dv1qmkA{ zyJAaLnq)c?#dn9H(V!Y5(4C^2!yZUKtaJk}w2l6!^OUs*ltV z^yPqEIw8lx=FPqI(o5zmU-=3JLfn5t=g^xg&D6}5<=rnu@-Mw$3R7byzPGtn)uma!3Qqw(9{$^cY?;z|97oFA19P{)_ynnnD@I|D$42(l2a!iUnz;PKm9kYZH5167)5Enef75`+8e^-HRwrwBV zXdCBr7h5SoixoE71=uDGXfA~*TeBGhm4d4?`vv;pYOMK-2{}c$Hmm> z=%}TEtKogdY=k6V5gh7mFYI{66!&+59=J_XhcCW4ldp=+Ol4jWPh|;l{F988vl6ROPAEDYb=oT9=kBWw^SvOu~2)7MN+qao)jWQ~BWg z-93eg@llzy0k6Fc;7|T~JHWpcz;rbp)BsQ;0wZPC-2gVjc8sA@>oA7dEbDx_C=5Qp ze)B95g{J^3pN^aVD1%~!O29xoam}gWj(5E0 zqi?(O=42wdlI=s**pkM^#&jZ)hGf-R<^Jw~Dra_42P2DMoY#3be-z-nkJ1;`_*cfW zWmdjz8?7)nMPZWwvRH!Z{n#8LKPpq|Yw>gWEJf425>IJRJLS3&E>6@4C}2yVfNu@s zJntBFSjlXEY~YE*eNXk(rFIn-Ei>`XCH#;YjuPf(sbw%dbPWIWt#`)ppB+HsbJ*$N zGaqYO+EO>KTD@vZX9o`qqAp4B{1W*3Y?2xP{!Rd8K`)d@Vu(}UMPJ=xA@kyB;I*~2 zu|wki=Vw2G7vs$3XyJv$gFR*j-vua+4&ejxNrP7cp{V7<5e^$zocb+y5hT0q9}ut? z&wfG(B;BPjjEgBY-4zvjfV%RC7lNg%+4I@7U1UtF17#5dh)H(|z+^<=nuRQ);LB!NDtj`3m z9%-)^cll=VjtXg(dlIDR2{%_EG@wT;iIMTnZkeFv&O5R2Co5{R_uwdPuHi`Ci%v^d?z{u;!wX( z*ZBHIb&kLIsMR^ha%_$T%$rN3c>J+-Z~fwzmm_kc85q2{^wKU<*#9zCVg($WAY1=3 z!rUN{FqE#%2qsg3AL+O|cBCWFCD=hqArV1wxPDkrf$d-_L=yM$?A}79J{^ue4vGhJ z`L-zkgBVu-b;-KOSgO%HI8!M9q`yC(E95zO%ft`i=cKNazOMfLhyMI9(|KtgH3HP2 z@C^WNf_@2s9jcDYbfX@PfB2TXfHtKk|{cn@yK&L?wJums@f1iF_XKtVB{+wWvkT z0jYyhcL6BxytL!BK9bJ6c>B;r%upIHIa6ha60(D%==+QoyDgt zsXQ^cHa<(1(+X1l(C0-Rr5E)U-guM;-}0N5EMfZeboYVX5BD5?W-N&I7wfR`hPMMq zDt;~;2&5~O0Z{3Va{Pz9u(?>E3(=Ee6()R8d>_y0|L0$O*B!=Go&}I{lp{Vq64+EJ zSId)XKOfvLne+#V(ksOIx&UMG+?46aO(ri(*R5I8(6k0gX`Hi6rK0x))K}|3?@Oxk zQJ+n#G_Mi{cy7nSPP$7bliUt4`}_LHd2#K=T#UeF#ofDN`KO*RrJ;cWz6+a(#PM#R zbsz_s1-{T%C`e_=%QS*XVhID0237?w2;mP;n<0h;5YOhd6*#c11@ky+u{;zXnDDi1 z;95K>iaA}B^FO4;gGfRQwbr5H8EpDIHJ!)Vz@x>U;bG3^I+N3%%No#k0qOf&1HLt& z<@gqXZxy)ip@h@uDx+68I%`XW#+SRP9Ej+g&oJ8;xsq>PW# zIl;uPRmTTtU4vP|U!_25aV0IV=Dh22J@;Zt?E_B;7! zTE*F-EUx5ZUjM3~x^jKM0twg3J#`eF&I{~M6x(jx`joNq<6my;y1xFFZJBh#(w0?g z)A8N|i6Y*qi{OiExJkggKor#D9skHjx{G7|jGYwyf3*CU=3|?q#CHLv#!YjgK5}_` zYx{L2vt-}%&%X@AiT8rJ1JLl}ucdQ$h$w|%j`>mH!5;+XlQJDwHW z+1VMn@wKlNM)zcMtI_&vu)nh^w`+%)dEr^?^-OVDhUViWT{M?7fcC*@eA_P0%+j4o zy5bQmxMAP@u4q0Bvv>$Q(y+9O)3TYzrTBF+Z08{a{G49cb^9OOlJyOdL*UU* z4i5wm9y|!9$tgg}JWe3IbpKzs1UTu>wiQ4;H6UJT@(0?&asERAj_hchM>A=vAGhIo z<-e;RHQ{r{cu)XO43?tN04Ft+^J62%?AvWR4(wU=y8Ps?ziVm7?|zUSht!2)E$x96c^#PK~*-5|Cgr9fENr443{-ynnwN78y zE-Aa=i*C`lc9`*3b#ozAhSkEADZheG|kf)YW z=TOJc=fy2Z>Kok!@b!$!i26W#bvG{tzz0A0LG#XczB6nHZhWjmMVCiZ4rT@~fj%F^&7-4Zh0)1zPTD1Om_pAmFB$;4s^v6u*)o&8cto&+W6+r-2BG7?zrbYuSK=k$TD@KBO|77 zY6=e-M3WhAcU9jT;NaAO>AIv{6CcUqv^yF-KO9V& zB!Zx_Y;}t?(uWJ8`w2Ve18w+BlpA(OyQE>&Vfcb@xqx?a8E0DV>Bk@0^&gEbKOJpu ze>R4rbd%{uyl{X_N|jB5(LS9dJvq`R+v^{b|_sYw}5v*kiF zF}20)-W`qXKY({WpnUDOfu(NfV6ap+V(?4$GONltc>@TL=*W7p1?@H(X~{*m6$i~i zMA_D%m@on-0V!GPB8c^}M8Ty`IZ#i)HnW3DBY`7m%y0AA7Bk9jrLd?>poU%3S@YB3 znc(TMNlxDW>Rng2)g;hx5px}t!=Hh{pa`IB$_%QM&9 za?7J_D^_n#PLHP}`*&j*gpaE6Rsg9cwC2KW-uZuc(+!)9(QgFU8DiGC0NprdS+H6U zWMHo#8^wIKoCtEURmphb^2Ljn?(OS8&_6T9$-fStIyI$oS$71u@Zg-lG|uCsBXyDL z9}z6XmFA?ih7ml{k@zRgH8t@pcIzg_$E9L?DsUAlxg;1FT2k2kqA4EOhbCcfr!GZ< zhz+z(=pkbTaf!gU69H!mX8{sdh8kgEy2uoN#F7wPi$xrDlEG$^3Zx(n5gi5SpUopv zl+t*!ZYU;sxCP(H#Ia1ZFb^)CizY zBZ7JS9RV_%7wPL?h@No{Bo@91AB6grO^z?8i2tA>jS^`LZV}+zuAm%`rS zL-*eF1!IF(-_p|b{tsV!-A6ui!|PuUO4DL57lI(M3WDF1N@b8=2Py}s4$@l7U6met zT6+O>-W>x4KtDTXkq6<^F#g#Ba*>|s3bse0l3-)Djg=IOp?MTt{Bz?+^%ji+(PuEM z|GH7XRq>kWZUysv-s8dw0__qaAzs$BHKmiMd4Bq|d>@%hfMFqT-|x8aYFJwApL6(w;C0pE~|i zd6SQ{=jC0(B;F-VrpozTu2?wOZQ@-ona;^kv$>;f^Icmnz30>Kecu~FW4_osb6|XY z2A?H_eHYZ>y-=KZam3`WlRkYNoW6gCuxr6J)9C`p%V`?_9z`HIlx4~;J^Jnn;Vw<$ zz>zi+`J8atQQv2nm*_PFN@JxGb)U>j|Ge{=-7iLBzsz?m?N2UUg%1iOO*uCMTrQkt zyq?kgmlZI&0ws^fjPVRzy56j+uP=ARVmu&##|G-H02%{&`4hiR{;FTXxfl3H<%G~j zg?W@nt5>fMF@HKe)`r$zYevT}E4{eO^wlNLm5_iLkQtmZ-B=d zO;cTcWD<6CfrzomaafTj04ihOj(Xyp%<&)U0~-jZ zb6c;p$5`>9x&?y5;C!{dBR& zm9oDJ;Oi8o=?+neTVfW_YK zB8~)vnnWM);wPHnaNRfnAhZc&a^?LVq}hp9TP=AA$L3F17rF1`fu*n@$x9r?BaYIX zh1sxdA-OudJRHs>n-pc?%tPmuAvOY6jX3$yl%1I`m2J=q?sHjuy<|LBR~q83xQBu(aL<2fhwi zCuQLv)i_YjyH}t9Whaz-5Dj6KBg9U@_*cE+I7b~Kx<+)9gsWR$rEe;87m&2w)%fQ? zOnFG1M%`8{6^q48U7hZD&iwroPaNn@r=Ol~ZJ&tX?SOb)JtjODdVGFIbp@(Rt&*QDfaT86Z0y)GT z+aR$1pz=v!X)u|~yzsOb>SLEiq^fjU{+!z_oSMMuZ>e6&k-RKhP{df*^0W$D5z}oB zo6a0;hxHJ&?GPmVu-#0j4=J`E28hPZAdaAUY&sh}KQ*P3b_o-L2s!XMvHKT|h1%Ny zgz@r?02%^nG3(%=ug(uE>`d`3jV+;T_{%PwKK@g%z+W;M12i6(WRhngOtU`Es*z<;t+U z4}bBCYq9LP)(nrVE_HXC;$T0&qQmn6?SQ3X#h+}?aqR_1g)4s&mlT0f78EX0BY4c< z@(|ztOF8xjIf&<7gxfmkGYfwBOB{wh-0E~D5l;$WG3tU6j|RlVkb=4Ma<&-!;NYSB z3!}rlk1rN2564EB6S_|L{sVu0Sd9TS5}2=c7eEJ#Z8#9lbfyjg)a_f!=%4p zhrVT*g-e))gwEj$-y9CoDrJNhL_y9tn=5t`mVd~zT(bb+lrigPJq^Xe7sPIL*P@XL_&84Xb7k=z?}hq zcR&X)eLD4R?ELQ$6cB!bU-Q9#NCWDlOyE~#f)RmQSQvItZ4Z4(vzbG=VqrFog-Yox zNN~@=A9kFV>NWZ$oFyxZ9t;@HCnI0{+Fw0&FqM9`xMFn>>F9(}j=8^7;zWXEl1~UJ z1qr}H1wI=;q*BQuA&V!>s2=~Pg#W^Ov=Wv~fU|NkAjP8MOwd-GpmUQ@TsHA&7F1vsJuDUp$m2yT#o4kXuIY$`e*$A(n;8BIPNhCuc1<&hjLR>ZwGqs- zfulI!VI-L{JMuyK@qt0yJcfyi=KzpiJNa{x=cMo70?=mw2%l{SKz9@TL1H_L3}=TU zCE>(dVEkvBaLHZ-+lT?n9jpMaDHXEQCXZ(X;{DyGb7ClSO*!|rKijbO!+&<$?H{jy8^COU^}Wv=={$S6mY{C@KZbfSs$6C^;Udb~2iWJ~7 zu^iMTF%+1=)_*aGnx}Cdz|Y3ViwCng3awtX20-oP@9zN2HTlauF_uat)ZI_3PgD+EzEc&HWUd0G z$R4L#B!nLbu;>p8vI;ZPYU83um~c)zrHcBTLrVB5O&9Pau6^LG__-hdX#1{0=|_dd z%MT`2tdTFx;q3tGMsf3?|6lC6=M%>0vjAF=Yo+oxtk<@}{c?VA4k5)oDp_Doh!h1o zn=h1;SX^#hytMr->o+WKYi{QEgeh=I{ODrBHwIp9XVEokcJG9Zfr*I;bJbN>N$LOh z7r!XRK({fgVVbNfO^j#cl|Y=n#*ZfB%xB0p1E42z4nNF_|* zEWzQqbb(7@Rn+D~94ITi5RkkUi4QihaA9AT8S80~6Er6VPL zW_J6?MDZ5~4;F$#jsnW6@N_`c>wtPoKqq~@JwX4Qx&?s#hE8}&k^-W96_`L49{<@! z4pezg04ow4c^xgsljYpRM5)lT&m?)uV0O}M>1ey^x30SK*WZ8FyRJpo_^QuL*XU?| zXmS!yk(PPNAO~^n;H5?H8v+bFQANl)5mk+x!#+jE$qaZRgs{JsCi6W0ZQZDlx=Ed{ zKkS4+c_9nskGc#|z}Qe}tS|ps$~olw3}d%BfAHdWzDrY6Q#i$2ZkGl5?|t{+_Wq&g zXBIC#Y?drFQ9fWUo356SwjjT_Gl&0}bog)_`yb??T;lkw?y|-Pvo4d)G)HiUz)t+S zd#JwZj@cFxR_Iuwb&SvIPS^losav*esVW>dL${*f%YuWw@%;XmO<`h`vpSyNkk18D zf!YS5&$6_qo<|8(tN8l*d87Y7sq|60=^U66Hl3EXY$4Vu~E4VfK1#Cm~AJ( zza7Ax0DT5PjRHS^?JfWtL#Muto#DUaD*n$H{!{j>(iU-mx`MuF8~{lTYiGg~fS30BGAMURuYVzHiY5Aaerd=BQ>2DEP!07XQZ z{<-WpoMk{$hECP^w+h5ojj-sC%7FCs2g1@k`9%wx zrx8H?S4`K}QGmQgF7OOb`v2`%r!X1*!Bl#r3!f~*y+~6I=a}JMAjGG=f@jf>(q6i>K>05+;A90F2g=;e0x)iQ z?gc+>lA9h6^1XXaUC$n~esc7(_cW&8^Y^#E`QDG;aTg95Y*~ZuMezi1d~rJ6*pf=6 zoe`khdTQCvHlSI%w7~fqM)VwYN&)e~7y7uw6PTlm3!m`#mvSusXQOynF9NkX!^Sxq zRkul_=eX|%e5mup2q@Tx14**PFaGwgd%iz7^po+{McZTRE->+qMR+p+s#BgH^k_=j zBkJ>7iSEOM567ziCDZ)yU!)hW2bN2PAd17tIt$auOB)+ju1?j90YDl+%TQ0KuBhD& zP@Tb6a&Gs1M3o8*T6e+*z-_nPCM3}UuQa9;g|0P2gU!LdE@Os<$`NeWM6gn(r3OdN zkb=CdbBielAqG-etXweVs;Y1~oq^{{u^#Xcusn5jux#3YfcvOnSkyOg39uH0;Ijn+ z6GWE9O#s0`N?`E73Lf*WHv@&DdF*hX**!d@leJi@z~p4E7gzSW%J+R;@$1CzPx>s6 zHR^?+IL6N|cP8;4)DKlSx9*@(C>SCk(U`nCSj3aPxqPmeA2@8HI9YJ%{@t73Ff;L< z53X7HyMKDe+iy4Ri}po_|PQaYSH^U0pVakx`tH-Y6gdb z&w5|Rfs9FX)eeeNF#c=!FI2XbBM2!7bsKexZBK<0gb|I>;+o7vm4AlMZKrfmzl>+A zsS_FJqffERw#W zI=(OHD-Bg1Y6;NiB(K(h=A*A+1S{@@ECPNj_}Xi)4GV_d62nRAn*dl>IMici_Pk&U zgV-ab=9C8l*a-Z~D#|uUGCQ(LnAp-jvH%Xa97cq>bmv<$LE)OlTz1$Yo!Q)_c&;cd z3t+O9ik(5`spOM}Fr&f&VEHlZ*^ttccrS2Iv@UpNbTU6NCFcVdq19)*AHZe5ZUN9| zT(8--1Jt^xwF(?jkozogByTNG1SXVb+QQ+#ZC6DOMJ~|9P)?Xc>j2{-TAzvGk>5a$ z8iZAl+4o|4)!5j9REiUn|guuYXUWXs6Uuy^_Jl9NAL-jd^WGZRUI*MPCC_VmVMP* zp=ErfQ&(Am`Pq*~cg17RPBb(=9cgGWb(v<+pI`Zas&x8!zVyGcS$)UHlgfXVjTawG zITAJPjZJ19sbwUO}9ghFoxN&1hkB3Hv zmZBw>nbEOTg#%qCi>Cp3Mlg;+k_Q50O$}`2Hd|B`_S1A!vGkC!whwk_*)WHWUxs9J zd1aV6G#z3-O!6tN!wbvy$`u&f;T$;u=9{iOwgYAg!QMPKrew*FM<2xi@V5Z`$=`n; zkZ^zU_qPSq3}zGk?jd@1Ilpru?b$`g7pvW^;ib6Mc+~`&SN@AE9!dYOU1Svv0NZ-# zCA>xuk7L_%#^n0&>C6Lr%;J&59XHiQ@A{kTulc~|Zh7-PS2nir+r)f-kas@o>*ILD zwDJ^?Z|&>g=9tyXZ;>aVEbSa|=(Wso<VkX9!u)<*p2t&mey^Ec9laI~6RqdcI+bU526* z8ZmXrWCUN7F}o(G%|nL{7Y8OM^+rD5TIEEp27s>e{nfwj0C4gru3jvIf_~1d{?S+K z7C8T{tjY7B+Fs{Z%chkbfk8~L%)_Zdd>95#`d}yrrNYFRF+E+Tt#{v&E3y;s`1QqY zpZwIdSHJ)EOD??}1#;q_8P8>l^-WFn%NiOQQk8cJeG9+V5a8J2MdybtH{tg^kQ7Exr_jyh<>0SIx3UncB7+s+@DWFIfvG?qup!Fz(CX-I%Fcb zyustrs1`@+W8x%pWF`iZ&cK>ie6pP#cga<0e#GI4hadXtIK(8*LOdr!&x3_QB8L$# zgBPUgr&WM`rU1uN$!SO9^-X5a=wRu^p`jeMIXHP!SWC_T&`Dhl0s8)>>GWrt_*oWP zCS8GlZaBvavf~vy?(oFJkB>Va{8!?KWfSmfG9$9ixd)D~4a9LvpqS_TgF&Kqf2=+| zY?j6n_4OUiw={0vTx`AK%J@J0&DWj+_V~>Bcm!4=4cugXA`!&_12h&{6fY`6b=q~x zi#j2Ti)gy0oppW{PtdzCE`+aimvEnFVR8+;lHWw0*=HBA+u3m>r+2OJ|FNX zKuQ zWH`kUtHBb&;<_Bfp(7qw@3lP&<46y~Hj7kRm9M5f!1rqLf({Om3$V9grg6XK`E1cV zHJvXFXJPT!iJo-e` z{NH_toJhm0r1r0k4s@+Xm8qp!Y(ci4m4+Rn0mJVpuxKi;76Q_ z(W_FcR$tr1xDE5SqH+=QQ6!sSxRAG(>`Jh`tIkx3*^n)v0+l*KvPjXW*GoqqV0lK; z_)Oqo91-~Fz+muLUta;cyi~}Xz$u)y2EZ##{)*51TE<+He{IW<q2OmHo{X@B2a!pH19LJ~43{FpHp%~N%U}cm$_1Q?36F&^FI8D>|S>ao* zRJuZ9*p627q7t(qi&udP6>BM^6g)mXLwmrt|1T&Ilxb}r+} z6;3DKv6%P2*x8hJ)>L_L&5=7E05FnO? zUwBp};}>DnMN|p!NAkKj@mLID1PPuES28kz`P3)ldC}pX6VEzGWSY!GU4z**K9%no z9wfm_AR;GjPU1SL6YgKND}KfGCw_nOXQi%Ugw9?^E{46cd}YT0vtZ%Z>E=HhLAkI^ zs>mAUgieHsVgmqSB14i$p=2(VR|+hy7?%BY=_sBl3HS~a6<2)!ZqqR}W-jb#UH_IX zm)w2-J@391CE*1dGqZ1Wbh;m(qQvB%$l&WkFhteT7i9<>wfLoaHlgN1^sICsy`}Md zj{lRwe~|&p0}%}dDHixS@2V)^6GX%G%aha7r3_a1&W--%;ONUUiE;Gcxj;NOyNsP6i^&l4zH1vxJyrgNwi? zn#LvUbwX!cCws2`bq7FU^wlt69yI{ClA{5jMgW2}-6iBKbe6`p zV-gPg$e4w=!CONRq@4=>OM9wY7AkFDPJky-2h(n7PVRzHkw~0lg0}<^=kbC_i{|m_ zY;gF1NssoK)rG0GcP(4|{x5yv_wO_tH?KxnI?(H;3I+KBQLOT?pr+Lt1037h8v1%^ z)6N>7G@ZBcFH}-4T9O?X|3hk{ERQQvvc^N4b3Wh`oMF|C0D|OZHu@@!>4zO6=m*8{p@76{0Pi%|ILTrZj7D_VC4xlyG)e^RYK&_e93}e z3!g>9bRQ`e@<9w=DqE3Cn9G+eX^0KhZ%x)Y!Vf%>W!#At9mQc}>@uxu?N ze(dfq{^Bpf_C6E@tuQ?{;EO>Wg|0oO*s~vc92$=YJHyHCfUpYGtvPG`5QhQ3o!VX> zf#p=-(6ug)?;}jOt4FINM#Zrl#=urZP~RajS_j(;8@XoR__%qbzdy2{hriqH*dorW zsNDrnLx4UF0QJ=fzK!ZEA6oLL(^!$ zZ;)lytbOs(n3rvrU)Tp2>9}Qv_kn}_)Ob19z1PHX)Zp@o;Z<+TB=7#mH{JZ6-@W0c zx36z#eho5mKt=FKLAouKsy$3x2fx1(m`efp4LU2rXB7WcMr!@Df)gjT6Qq!Tm2rfi zE|~Dm)~Cn*$BQp+8)#|&d33|3Vq)bQJGA)WAq*>-cQm&v=*ZUDvB->b>3=EI%Xq@$ zzn1SB_v+AKUS5naW@&4i*|cIsu%xw>le@eg2m^rnfR`Eq3{wxN0iZhqx-f8x3mDEZ z;e_4A#;ip_%L=2zW(Lm!^)sYB31>reB*r*5WH;Qds*<(P;h@hrfhnHlrcp@Zc^W1~80 zbDLIo130nkYJWDL>94d4z}mG1(yp`oXW{eT$pE=xM-L>aM%J9{RQTp`k#c7x`bhbQ zf}-OCOgw5ZQo?!RI328*8y+;~z+SVcr)%x?#q7I(YwgNUeC~~Jc-O`YHgBLjOqa{! z1Jl!dz?4S~*4N{qL4-Nj^wNpnANaN*K!USfvEeiMcmBu!Jn|o0sFMFPnGy5Yb{$tT zs;~HJw5OeURWmxC!lMEd$1t@loceYybTHs4 zTzyW?`e(Dcva~?)?N6A;!F)`qQQASMtIzqMSP;ee6g>59GTmhMN9)SFC#JIKBv%ZRd z)_dM~_q{llTkZ*B*x^=Tu^2DlWWf}k6JQ*duMmz#8Jy9^fTb+xDI~RY1r6Z*Fk`iG zi)DY2Doi9!1#iCj&#G*_Rn__pJD0;1Mp&jObMV>jSUJ(sLfuQYXptG2Xt`E1$J9zvMMwasY)Lixq!95DCbHq&$Ypww3^ z=|r!SxvuLx6*lm#Yq;GuO%ZU`NDB;3SU!Q^bGa z1jQiih<50_?@@rf<|V6t7)|Bz>1paw%60IIk>RexCh};ZskJ-4WQB?1V=h4fW-+ZR z8Bu%y$2rGW7e|>4{dVt9UNpu&3m{_{Fd5sn-qR-wuHBGpDhccq(lm(WrcHBhGPN-g zTNH`JI?>qFOsPa#&^XXb4FP{=pmzK#S;U`Z#zt|k;J8Kp-S2*vL=x8=P4Eb(3nGI< zozdPyFa{<|@=zd8N~2=)oYi^!Ro#a~qIhE%QF23ni9kwNJi?u0DeQsZDzGXp=L4{0 z`BOaj(s9OZn7^(L_^x#*o7$W@-9$3@);rUT%69~oM5{Xpt}LO(pMuv z@Bgb$xEcZe?En#O*KF6MBf5m-v)HlM-hgsiaFxch+4#EV=BCAsjSW~W>CS-e4yZw(%0PW>hwp217rHO>tK~^0 z?)X41;!ol5!+bW(-y_FAI)BRfzt9PO8rny;@uJf(4hJlkhlhu$dpQA`zy0JVdiD;E z>a74y?!43xP+#HdtKm>P z@gu8OcXgO)XRWgmqC63@~xz;}2ASOosMG6;Ni z`KQ?|`&_{0Ckaz=+>I&)xtW=A45tj%O--34^)04xQRmjCwQFL<3ogigsY z;(TZh3Xtb=WicKQ<|J1(`}d9Q8yN1pe$&SB=un^iTrHmqNO6PA$~Sq*2!5R0FvjsX zhyEAb(=h&}eYRdM7qAO}X993o5UxzRA+oWdKC-?POFrD!$F6Yva?I<>-w$)*pKbC7 zxZ+sAF*)1{2=RaOum2X0$eA@JUufrZ0Q^8u3HL4VARzB;3az<{W}oCwc4cIh15JtU zA*linu_T|UNlLeV}4z;haPC9jjczxwxY12A0;0QzbK(1@TAv$^Us%3%mvfiAZ^hCN-v9CY-eT5nT!9=^h`j3XU|~JV zNx9dCc#A-l1k-Dk1N8teR!yhAjV;Vy*G8eB5=`i3`C)lM`H{;~G^91Vgq$dYOaLxp z^xcK%Dd+#fB=dr4m1V2tH0;`-oXKQVZx$aJ>hBwEYTQw3Xr72Swwiba{_7z)G7zpDAy+Kqcm{A{+xCEU$B%uy$$n*o{mcF!xnL0*1E*EAKo^!BQOt7 zH@7_=TfW95I`EM_oWa4XTnsg*KMJo<X`p79TMg=|>C^=Lkv&+Y4;nr~5U@4S!>h#Fop!H%_4!bJ=JVm~b5DNJ*K{`C_o0_O{7-)B z8{YoT*8LCN4~E^VTU%=vS66v+Ykj6(Z{bB3e%jyz1N%Q$28`2zA+`wk6h?B~0>$%@ zG?gv4gX^7?3M-xKT5z;=VmmR(q1!)|zl3+uK-T7G12r_l$Np&TBY*vg&#lkSKNlW+ zC{*xJJ>JKO^Dw?W2peOt<@nowbpMyJ5NFx=j8Im=Cj}SUYo{J&)5%^-N!2=MhIvQsx^xQdv^9@Fy?-lk%uf>(v_h3;$4@)NT1#P4@A@gBm{D zG8e9giNWL7Z?>;4-IP;%TS2}skzqXfP+;EREDknqKT z3+RG*nv#rDIH3NY+S;3&;ttaOUSAoH&;UDBddN76*^ao4U;Tyu?egZ#%#Fb*Y+KL3 z^)ZGA*%FAHKqoG3enWWF_@CO^%ci)4w7=Dp_J3W7;;DzupoXuBo||e_UUkpug@x86 z?+oN*&oh4S&x{?HE(Cm$KeW&%!JfnK{oe0|=dWC$vL&F_`vz;P=ekdSA#|U4N)`Z> zX}J?a@`X@!tOZ2(0G&gkd$c#zu+sAa2^;V9&c*m(R z#0qi^#!%&lsc|uOtu+%aZB_fvb^3mbf4^3#;y$gxsL8*0Gk`AueDY5h0Ce7TA;4;f zTT0B|?GWuSF7}T;6D5NIQW#0`J4f;&qvq#S25BE=0W+dgcslX<-P$ij@FOQO>=R^* zn{Ro`P`9&L>0ezBwY8~mZ!OIJC-d{~{2yNZs#6~u^gi)>fAYtl`^$~>r$BzKGZ?fM zXJ#5V*4DUKrEhXDaNi_T`lAO{Db*&i=Z#COx`&ke)&Gyu{$|#3(e1d&L0_bgx?f7% zXf(39+1c#+jT?jT_+PCpwOY?~r>386v}PV`G^aza-@z9+%w>TdjY0QKZYwPu;txZn&>EzGF01wXXeiRq>?DsPF5V)=I z_@_Q4gT&)m#`iRx>2Itx+n1h|yOnSOCac!@WnBcAM*y11gPYFNKHDM<)98+z=Shr} zR$5;3B2H#}%a`(UGhf0WEeja(c-b^3DF6cYLaZd%3SQE<*xm|Hbvl&|RTw95-Web< zU@iju@X6lOj5)aa0LwDI0AT%o0DQrQXoqpJfAqH~8EoU0ve;IdN|CQR^Ab)+v*y^G zkDL1r{hwRbIN++-+HBzUg0*@E=j*iBR{DbrPlvf@o>+X%`qDSP|AG5|@WYX$B%vJ|IuEf z?B;e=n=8eB+J8)xdJM!cOW*|=xG`V@UlW4N^yTdF&GpZ%)h7O|vT$mpanF6Big(rH z^PDng!I9lxvhc?@|HXHN5bp&T*=F|vk4Y43R`{^T0=c~bT_1M|$|rdjXXe5^^9voc zlk*JwDnHfdivV8;qCzfnZ{_-!u+Sd!r!6p2b79Nf6x=;9s0eLl!cQ821QK|(`B z4rw+s95)J%dBQ`jKz_t~UJhG68A;&j)i9l9#K?INp>X;e$-*SwcihLI`?(u8!e2fA ze7LrW<$zA+Sn|Yo1akr4mjP0kIA0W`ivc>NAE}E0{lW}Id&Kk+*`M{h3~B7JS}8T1 z`kY%YEl*BfF2y^JWr}c2-?IHe#UHK-$fHtgwkGfywMutwbAT$@`>l_B_F}d1m;DD{ zbhY}xgTOXIwzY+C3+gh@ZA$(Mr@y&#=lR1p;*FJp`)Gek66H(!Kj%~iu6S@)K$u7J zB%WTI91PN(fOG-i@Tf(8TFu@c5y1P*MF{>(Wq7M8CjYRyelA?T62cnpvE&B=aQz%6 ziF8zyF26jstXu>>lM`E=FV%n(^J>dULORR0EdriOaVehTc`7f(5(#{`lCs`c5tA+k z$RlDR`LM8dBfLCozu})g{J;l(=(|7ows7vjGmwIvnP&x<|LarW zl|DkiL4^Z{AH_ug)80ytfjW|~|NWoMuvQ(m{f|V0$FoxQI0or?{E)!kd&Mhhwch&A z|NNCpo$iI+z4vZrr|?Ei&Rh8Oo>04GZ#Djt@QCcMV}*_y+OlN+gIIWFp!D|^Um3W* zJaul+#d8qyWIzKAWPkPr0psE#pxBS4l|m3Em`dSYtGaW1P@)bTuBsWu&~7Bdr@+IeJ~Jmb!F)h^-8A zv;BQ1)9?SE-uvEnecRW6(;ML5_d|;6 z+SXR>+|11E{d03O5Sa@BA4E8Sj9LVE>!gLC@if3g587thi5g98B9gd-NVttm+C=Y3 z|7RgDgE-ooxHNr0_Gk5FxTOYYEH&70oSis#AMqSxH?L-c8@+}3Yn9nKyewb}cI3-; z=aa8ekOA{OC@gt~SGqi(ytfCVVxHvZe1w*0{3#3wG*mplbA;QhvMr>qLOnOC zb!PY^&K&^R1wibRd~wnzp7c)Z6F*~Cm>x*Ju!Gn@?4$Nb)2bP@5%F$kfuq`Td_)Og zROBuEb3T?$j#>oy0$ZHcqf+@V$*qil&QsY4mGcsg3EvbC*!g(9!p_R5ygAR9C*@R@ zTncaip1vz`6Xv6X%~rLC4|i;Bto7Q@pAQXuf$08A&wk0*_uJq3BVY8$5BxXpe)rdh z)-=x`I?t`HuAg67>4Ilt8utlI=%a%^`KNo7ul?Gup^S!ec2L*?1D2O?S0Gq%M}W!(Z~l%Btd~IsFH1NMXxwb= zWnrM8RmalO!MVbdgyKoBNnj;|y!;@F`NChe5uKc*EXcTu1po%au-s{f&)mEb zo?69X2WM8uDlP&z>HBVg?*w?-7YM#6C>I1!)`(#CvWNsnWPkSsmC<~V4k3OdKlC5T zR=>=B&jt`HM3MxQ66ue(6*TV4;(bPQ7wrcdjuK=<<^ZesnhGBytY)3-SMV-@C&I!r zPn>%3^3_-W{nHEY`}yzr?sqg^^_oXO&$9=P1+Dd7uLZeU_&#ZRiNMb?d|}{&3M=yi zpumg|E9_hU9~=80mgbIsJ>EMdzP7T$@tHnc`^aY>zjC2I@$v5b;^(UTqR>2UgTYJp z<#9oF4fv__Wt%RfR~xKqvHt5dJ?1%cnB+B0B}+tHTnA@fO$N8@@LuNP5@9b4C^4G zUl71>+mSjt`>QB)2|pZ&X_5#T{V4HG5Qy(doRp^tl`SD*Clj-ztc<}Df%b0O&$AaE z9Kv|Uzz}K;zBx7PZmxyS#iv8<*(bu8rK|UT%}n#%zx=khzVG|~{x^K%BPUM38Zz*G z0xUm;R}IeKm6_=xzy}x(CLCz}aP=@|@K{p^`@4_*Ukx?X7)v-#Y%UT`k#LO$xm-iPd}HP#S;Sa_^=k=6Tr*7I{&B@NsSEC9Baui_<4Z45Jbu{n-BU`Wgp2AL|ol}_MsO7Aq}65%0& zA@neb)kE?Em~v1!<&QNC+R#7?*DDi)&o8gFudOU|V&?}M(_H{x1o%YnG4aKTzj*e) zU4$1phBhjOXwcL?DG~fDDVM_AjBa!ZdBVu~lOHLVPO=3wyrE-V5zq|r_=r1t|F^{e z7w1)cbfD71V}$KNuhU+_SHI3b6;57!=G<5G+wcD1L-+sCPrT_X-}kncz2X&UNfi#f za$$9KgYO;Y<$-B^jF1z5dL}V6kRUHr(l!mMh7RsGs$Hr`L@9vVB>;gG9y9xI7qrA| z*8nGSIc{FN#&MQ`7T@@dKmOC_+b2$3&rY2P*#w>nXk$|rr_Su->=$_$Q~O7UcKK9d z+{l0iS8(G_7G?*%tfn_RvOzVRyLun>e(JIB+->W#B-k}P`skyP=4U_hTPLxkcsRRy zb+LzSMV?g*F!y82Fe;Z8@W6IZI>Ax#f^Y-qASnis@*w02jb((EY2`$mGEo+!4Yz3O=v($#qy;6{d(cmVan4r&Id1^RcJFg|Si`@leXG^ji@nER5*avRjX{cBrt(jjSV`uwADEObY*63wK>sfotv4P{Fakn^`@EW zSAS{cBft88ejH-qF`qDjO9EW{RvUPkK)2tgkCUwrB=m3haW<2FZq)+HgQzi2?jIyR z6WJxz+-CnD2m8lnl)&w30N2HP{EARzeSMuy(Eqb1pIhE~=%MHOSI%G0YPFNR(HlLj z5`Ov5KKkJh@_PY*6(4ec0ogeCg3F}C427cjI1mJfSQZ0FOyI47Gh3Z7xw*=T-p}|s zxBHRe(#3%HWyV9N??{gh^YeTnQNul_?^(o1@Gu?=TnyK);fi=izu73#J5?mt2Cxy< zkQhtr3iPD$mI^=RL*qzDc?b$WDR1y3+OrfgjFP2`X!6yjt+;k5w!s=dnHqf#$r<#+^zuMDz;Mvv0)Yb!V>ZqYfCm_&O<2cW_5Vc3 z)HVq^)|KWba0DZ8d-hMND#6>*fLI1E4sr|C!|HPP=KTD#z3G|HSLYV9`W$X)$8^V= z1Z6%UrOYddtzwm61J%{F z6V;V9>>YA=&^H9)tcH(WP<$MEfrSYMjs2pF(-@vR9FfLIiI8CHIKV|-E|lY~Kw6jR ziu&@rgbh(zugY9$;H$yBY2@FElI`N?&eA8RL|DS)^V{e4$ zb2v7i$6E$bxHZ{m_#=d)1{WDrK<_a?(H1r4S|e^hf~z*szp_nqy{G;^F81FKrM!T6 zxcw#OB#H0Y5av-2AOGXQvllO3YF8Rh*Uvn#);Mzx^FJof9v^~;En_W$oZKb+~seJUlmd;bFfQcI3xGOFw-917Fg6KDtT zX?W)5&G47!&u7mqEy?7MY%TzNqW2vD-~RX57Xv#j1SsyVB9Cmx3mLhCy{M91l{u>H zD4gk6vOM2o<`GWQJ5(G=iuA^Rh==2LizCzRggc0l6Bf%_ALSwd?@-rfH76Tka=PBb z<5k@Y&xYnxpAGk}-fVsGy{BIDuGfFX`~T&4{)4xJq3i^pzHGDG<>cPP8#G(>YL$;8 zaUtM~0UvNk<43BE6b8uwhhqC#-6))iAz7a9v6o5HJ19Pq5Qqt5?tGGD3Es5^+!Er_ z;KnqMTDWm->sNmJx1V0C)V>hzdtkGAFW!sAZ`tyrcATj2UkrkAw8tbOoTk0j0)t3W zq<6YV;D|lMNf~bc%Ps&~+sg*H&0!+kk1r!Wa`MzvYhr>o?E2)N_Q@U3{z1R{0$>eq z|9k4`r(=^*%gL<0d8&hFjyo5g4gTw zd8pm_5ao2L8_gk}Aqq;eAz75#>ym2h2eUtD`&k3;UeEA>pbMRB@TsfUw>oWHWYO(> z?k%Mg|EO($&*uW5xC=nBTr`h?DudWk{UO>_%;H*78y>Lz&3jXS0jz#z{wXq=ubC^k zFDaeavfy)UN&e^b77G_CE4-B!T!5E4)j3qA$c0F&&xSDNuf(~N37M8vnaGm?I2r#m ztrd||vxWC!^+Wf{rBJ#2Y?#HH1z$ASdgNR0S^U6H|Go3=q=P8{ zJH1}GxDa3&KLENg1n)SIAHwao-^)p1Ca4pO#Wtol)iZKjk6xG6EO=q!2oN|eW6M(s zjgQx3I*>YymRV)EV-0Y`kmL0)dl~(&^MC)?KfAb8tDhg7KDib6=v@7G9{q(7;=KSF zcdzrHMuaT{NbM*%VsSWL%=?qshsA(eR5OLl5uow{j4f}k4k5gyR;if9T>vn{ADe5# zKo2W=tjNRS^mI5iJCijVe1}h5nfsQ2uhfgH0@8BDzWa&*MA^^$)KBr$IJ`T{@NR;z zIM`U9Y-10xef=`tK;F%&HGH&Slpa|Kfp_wWI;b87#2{Cg$pl8yRAYPWppad}<1(S%;DxWO zv$itmJoiMXKlPb#|I*bLy<=haJAV1=zV_R`>uq2E)hC)$FGaIjZS zOUQ4T%7+KQ%LkpktO{85orb*sjOH@Z7SU!&{}&v&xt%>e8vEa=K3>S>+!t_}tD4>W z@Wa#vaqDY~d`#f<%_?3WSgSWV>*1{0cMwQ}f7+YWZg-D~OYue~IAjSu<3sNM5Ej!_ zR>58CVZPZ4Ct8!CS(62TPyCF%AEr2;_LneO25o zh$TKgomuH^ZuDv!>-7n|UFGy(@bFj8p8U3#Jp8~{zH#zv|McfR@rjRq@|mYTv4lnP z($W%DQ=7uGgw*3kzt08nPC+`fWjZW%1Lx_T$`GJ} zKbNhpwQyqqssm5FmsEQoYmd{dF!X`Nxigzc7sCu|0q|Knchsg3;;1 zi-f4#=)qso9GKH0{f6MdzQKWpeZm*dY$;pJKE=b+#4(5_6x`FVmb21# z(*NBas2W_x!2Ww`c1cvw06ie}oeUqspnq|~t31{1T>G-t58y@m%0am|S0~RC^uvxAbhk2>Swn zaa;rt*mJrT5osIP%vRGjI(K1F$Lj5mWj8f(5-4xpr>T}Vev zey~LvB4GK%3YVj{zlvA>-k}C)d~tx){GGv-|L_-oe&b(n{Nw*41icsF=H}KHIx{nu zGrVIrOyY||eVjS#Nu&G4SonhUK=EIQC6YLptiXhX1CT_=jv6w z7g1jMiLZymod7Nf(#rzg7a2=`-1}kxAJ##s#mdUcNxU4O9#&RV^V|(k$YNAaxjC{( zBnhC1w9pX`l@YJ>I z;q%w7^|2@Fivf?*T>+o`J@y>{kICK-ir}!v#FYUWNNwjfIxPF=20)E6Aiz92Fo?wj zCq7F-NuzOEj<6SzLNv9}xqlL&ZF2r3&>(n+jgitur0`P?TF&+4{8JuQ3K8o{QZA(7 zk}RQ3+fNvW?vynqssnk|V87emSnXw(&xhIbPffgP?dI3M|GqOn_^;mb)&KZ=U;U-8 z0~6j4uz7K5iF<_2R-=KFDzJ`I+H^x z5>S7<64j!sRuyjb0!g`rhgjcvv5b}@m(jLkP8n`f1MWxJ(#@Mxu(-`{e&|C>mu@bd z@6FGxgnLeh$|P=G>2d+USMPfee@6l+H>QA=CMEEa<@r*S8F>*YFFX`^yY^RKAs5yw ztd+SWiFG9ND*6EdECOchwW&vEW=~JnCuWhs{>3E%C;#Gv?|qM=2~46L!`ZWEE0-=^ zl3MYQ5N;>fiVxZHa(CmL!tqwSWR&x_7_2{eo8`1G3l|(<_PKhAmA3F6iZ=xsvxaN z%u8BIkl88jsQq8W%VqZVGe+;y47M5Vt>URbzI462u`#GU`($-$W1}`Xb8_*-;=-Fw z-uo4E;gLuB|Mu7a-G2bfO{{{e{ce|IOQl(>)p7T7)!ty@{e-;PKRl*Z`~Wztsi85K zxp_c&6%(bS`Ze3K$W?;SIgJ%!hJhp}Et4L5o+A$0{)tqStPFRifvZ=q(ziIlW#Q)X z(kD0D&wc6Hvo|Ui@WssLM98{$vt5fDRvu{lF|dF1HKg&?qZSHY|6;PutY z{M2-K_(Wy;-px+y>E(``-D5X_m*vt$fWy>_&>-fVzH{Kq2Rz`DB0Se$tn|94D{Jd` zqbLppzG+1Ihjtq!k6qaTiy0ZQ5XwCng0u{UlMzoWMxEj>>FnJSDDutJvBmMD&>wM(xa0eZvO-DK9XsN5R+eM8&mQ zGh3UO@JZh%bD!Wj>8G$S0vwkv09bYLa52g_*TB)*Uwn<-O+Ce96_5U>VHgjb`5H^f zbvr434E=x4?Uy#Qt@s2X-lh%J;HE0vdc7QKosH_m)=GHs{SSZfciwxp`r>!J>z?2I z%a4EJcmDK`pTkN1)s?NS-kDZwX0p}lo?l+xV!1%(#>OzvuR=f3QLc2W5ZfU&gnq0qKe;|civ-wO~vH#gUA&o5k@ zY_^`SPPEQc@p257lKBMg&6r`h&(jSx4C8@2C|@v{v{vZ`GG~pN3z>_j93Xu)%r%?g z4DR8X*H`;;!sinL5)-zAX+L~1wDWGjTi^Ot(Ay{p;EQ-E0FMXuHdaIX#`B@OzRal{ z`-J4l;Pb1%f*Jio(HR(f8OJ%EF@xr-c@*O~rXWDfQdrj`5vg^Mj}$fE82OTN_U;Ep@OEs87~vOZMajsrCC#Sm5FHX$M+huFEkq|HWhd+qniy)I8{oZDsChQm~Oo-}oY z97XyveVZB(7r>kD+zqN%Zam-L?Dwu!CMK^;oVX`6=J<|%WaC9wdfTgyY`%r`=zF@)1A zopVy+n8zgOrAWerHQ>XGlDCS-9r0rHu-x7vI^7YVmvF-Ovwx3$5#WmhFH=tbP}W|9 zn}hUXBeRna<7(Iaw}0*n#@hr*{Y2`fJjp>PGSWOw5Comx+a$5!)AB=bQcl?&tpB^5 zGA+7nE`!HHl($FpfjkRXIOF`IHCY>ALD0Q+IaHqdTv$B+$x<8hWy=eRz$$0K zhmj*?NpCQTBW!r$7>M`abt-O5+fQL3Af@Bw0bCEnn+0*NAnu*%Zmow7-Zxyo_+&V< zc4Ohq)2(m$`PV=8-tT$a+u#0BbNV$Xf)}^qW}9r#y8qMANp_q`}U>l*ROOYnpd(D zi@kui1xk>IzJ|MX^cj?P27+Un2uCJhf|Be=Pa4aVqVhAuB4sDEMuL*J?*AY_S$;wg z9jMn0t*wo$+U+pOP(z0)PWs-j(nZ3~ZwTZEnUz-v|L}u9Fa>V+gpG}Pz8I*2y$8Nv zfq^S?i~ge@`ZvUOp%XQM!eKaN)Z^&*fWX~X{D_WfK7%qq>7NN}u1_3-{fx8!i--{Q zZrZQyV<*HSV4{g(A;ZmBoBi6#%_=TJRu`((lV5(~-fz19!LzS_%bVZ$$zT7%7ykW6 zzVO5!qSB4?*RSJsBcau-*Q-6eP^jPM>6iqHmM)?zyPv z<2DwE{MZ5Dz=Qj9LSwyMsco!qg67VfFQk0|;IZ!lFlKky`FjDAll(Y{hI23dqA8R( z9hR5p0$&fxHwE%p0d_?k98fUh$)v|04x&7ifz$)6%)c5dTR}OMqR5Mk$X8;wi0^5vtgyy>R;H9F9z|9zmI$lNWL3D zoWp6n*98HJmtlkkU<$E>WgVXV-7i=%Vew_cbPkK7e-meT%8MaGl0qkCr3{m?ED5w_ z{MCav!V*RB__p6$$fiI+7zFqjVXKxkCoA36m27}}1ZJLnV)DV|D-S$&V(J^d@6BKN z-gmwG+g}fAzjeFO?)4_H5a8zsThJ??9^e4x2M4rTx824)yuKTd>WgMk-QI5hrw!Z= zY8K^78%Z92e0(F$@NDzJ*&lV5;chfQt1&PZ_|)ViC%?gmf9`+2)Sa7uKAb$+smx5P zLG_KW>c+G+3z?l6AHMzfKK^k8;%)78|4OeDCfXYlr^8?ojpfY_6S((=&EZ5ZeF(8H z0vHo72Y*Hd)rRFvP4E^H$QS; zlCml*L8oJ^PQYJ1ydI4O4N$3&a>Vg!KYA!M!e(e+#KI&HjV@O-FUdO9rP zNrEqK*53F-FL~$#AN;Nld{tOD!Do-X@hv>#JdJk^r}qhP5x~K#zPYwu#e3kR+9CjT z-)a9R59gz?isJYjcbN8vP-WOJ4Phv#(gCBH^^cy?~)rL%K^k(W?fqv3F3 zJUOQLA9AgXj5t)2{*hMrDaLu`G3bmR>8uu+?YFR)=`|Yo6f*TDd7R8;A%NH?c*edc z@Yw0dZ>IxUW!OOjM{0kSN&S&tR1AtEUfjj91uMSh^itA&%aMpl={z)MW>Sy%Yn~pW zIRyV#QMLZOZpEsk%;T}Q_RB>QS!JWgHX2oYfiuH*H+uXQcXs1Sn7sIOc4MV7XY=*wY6GY0I0YqA_0O?a{N*M zqEE#*K^_|o5kt08hU8HUiX(n+?H^U%dF1?)dJ6V0mM_zHrvdC5W&Jq8W7;|~w;rZv z@BxeooWH`o*vH_n+`P)|lh^6CJ1qO>GC;0f`oHxxiXLz|4Oiou;hu$saAt0f6Z6nn zK3e1p0Z#fud0Y{U46(x@7euXUe{iC@)t;`bZ*T#Cdl5v)v}dpjQImO)ZMy`)j;Ffz z{XC(S&YP412uk*C)Y>M8^Ce&S zqthq<=wJQ2U;ABjJ6yXBgLQ28Bj!zljLB@Uy1dlr5AMU8$c928sdLARD?s9?i3 z1Nqq5f2fgV;?6YiKh}QY+e66j1;Aydu-R@$_rNT+o=vo_P0XCgviXyhHWsJ@%mWw< zNVCIO@RQkxMVv7l5Y*w}-ROAO5eN;ea^|O-VQzXFlQk~b4|?h8zpn^}Rs(GKjw^yz z@=ir`%}Mm`#Y(4Bt!&^`ft?PnrrSjUbSY6GxM8@{{)VAd2S2J$jiA5M!&w0Gb08*& z9G&nLmSq5N+J9M|%*dO}Sju76Vr3LB1o4M&2O@v#P7zH6P3O7XXLQNc%{mmfiWth3>5U`T?nz$St#LNa- zr4u8uq$N4yVQ_E^=#P#6A4dDlr&Y6fsX!mMFlX1EuS{UO@zmn-*_pY8vkPZWy?FXV zKhXTo{@@RPH+=e&PoWI^5pUaKpW~_^TfKR+fj1O!@JfU5bsMSS((GIJ|HEj%){*|I zn46yF6E05v#r#oQ0bYy8Dn$7^LIbJo6g~|5r?slz z5rack0szHwj$>LqO=-Ou!(1XCmUTYj)6U0Y!Hwdf{Qj=AUsQ-6vGd=o{W~a^Y`&>G8*Z z_Ya@?!e5|}e3|45-V%f{i33^MrA7C^4XK=I?TXmcDcFKJvHueuGy7A%GVF^6yvt=W zmnqBa#?sP8ccQh@pPp$p8_H>y zLxLGha3hXWBQ1h}3>gKH1yIT|hid|IBcZMjR6Z8bv6(V4=x9YcvS%k(0b~!C6?z~y z%Av(biX5v2g&=*Ufft~!VzKk|(n{|$*RF4MJ8horlh79eOcy8rQ8+Kdmf>rJ$JA+??f5{#g0{QMDh+rDhRCrxm_l z5TkR}UAkGRce-I=VR@m|oLpE~n0ndiuYU81>iL&tANzm*{l`&Y^YXQ8jV)Y$)n^X>P9v_;sCw&6%PGW__D z{0Jw#@JmlVy9lCt!|G})+rr}ke6a$*8|-R@syVtMplXh#I-ZIREKS(|gb*nUQbu6% z;h$tl0%#d*1?RkhRIWm2`N|I%SxHb3qq17O0#>0xNa~>L<8@0HSC-r7S6BGmfOIjC zE&_=6BgGT;g#$I>TJadDGTcG~hi-p!0Exuc6jC2k4;*$9@iz5MZ3hd;Y5;)!3lF;8 zu$P;sg5L2)7;Dfn!dF-wy#K2ND!^g4pY8OHA;T2TUT{V>=(o2*_saQDzw~rCy>_GW z+Np`J`&VD~>i2!k9 zzz9SBuc-2OA2i@@7S`9-3Cle9v%mO@D;rsMHJh4RlQ#wNYgpV3fLF3F4EIv=voY`g zY#b*bUfRY^0B+^4p|Nr~AYBCb#P2cl)^iaBB^ik<7S+)4AWt|d;M5ZL^M?h*qVL^~^C({8e-xO4v> zgZ7&b(RJWV$@nLJSpMvz2C~)FRkGt`HwYj3$jZu3{hMo*>6xv{^mM)hz>Y7y{rL8O zZedihvt1qZ;8psWPHT6Z?AgWwZuI>CAd2DSBwhyE=}%_s>vg;k6l%o$#~!TAgpOk< zFzU{ViRB%jhBc_RtrOS~EBe&0Os(fN?g*$BLk^7iY1~wEN6%SOvb7I%dCfXRPcOb9dF{QuH)mk15Q(MvQN+Y z33EZ<@yPoDqVmWE@A8_*JGxF)di^Gp#m)*ALV{V;NHs#w0*2ah4z?O69|o)&c=;Dp z!bOono%dsF8v=O+4r=;}2*#7DXGepV1Jv?*HS~ew9D>e>SKLccg*Oe$_J0_VarIwlU%4gD2f^ zHCuKCLg&oc&49byvk9y#v9QDsCr3IF1I7aS7$A)VKh|S`3`n>HfCWH(vmNl^06g#@ ziviyS@QL4JZ?EL>y4^5opfD^iW6<}hYB@)O43xV zNao{@Lq9-Oz7+9n>)1x;WyMG!7rwe^kdeSku_6SO#N?5B3`Z1?E`HZ>;35a<$&QCl z@Wpu43Rk3gA*W%z!?nM;gU< zUK)h@1hfdX%UGleg*r{suK8hmm@R2F2?n?|Bze^KkCKfXebpRo)j2MfszHrZgGgK!<>}eN?s9Od8FRXc%T6<}^+c=w4_kuB0^*hQJ9I zqjMaQsL>e9Kw>bXVOb=DbpUX!^soZlz-nm=FNu%>+b93sb_CLL4tp$BmOr=FfY^^3 zJ1qOtAKA~PPW}KCn1G@MNiVUJG<9L6bqYx#!zXwxGwgHpv$6C4ac{rsv{J#V2BFPb zr-Mh4FFuo1Z{ENy&$x8g?^N+RG%8jO*Drguuf#^#LU7T?#?$^Pclo;y8esR7?#CED z;+;1vt*mzY&F0EPYj(Xke`;AAJ0|@YO&_OHox_GmGPpcDc31bv?-FgfZ@>QXP z6aJ!PM=hLecvE(ZHGoS@_fWi(4tCJJEX73*a#bC7~1!5iIBV=Vvt-hSE zWdScZBcrJmbd!5b`Z4x@YnaNejf!wogUQb{0|}H=VL={L`-Qpw(9{i_?c>19$tr`J zS1K9aP|8IYUr@$wYs~?@>R-~@AQXe74I?8``paGkI4Swi1b+o`!!tN0{U>CaxyGp26XLvr>3hf zTU?x-YT!*lN{RjYZ66Wfyf4SD3jn+uU=AH_5sRTF7XW-D5S@r3*s@Bcf!Mji0ZAq? zIac8`ZP)ZcrNQ!?ggmVhr$BpAPbA3mArg1+l-~0Z6O;o#E+Z6z3qO_6L3@_)df@d= zha~9&pg7t4f}ltf*+&6O;C3`X{pG<@j*RxqDem6>U=EMX-3n>1PpYv*P5>-%q_a5s zniM!@{*N|{b^9^2uoF|&2)G)6A&TGj=Aq{+mZkY_r)U$ik>*CziS2ys7~A%X(B;n^ zXy9*O^0O}q;THD-jN*B1d8yOw^>1S4T*)|J;z<;DJfU|d9P&8iAU(cg0UmSjb3dRG zPT;ABa|;WVxycsic{%%s@8e%5f5%yR_sap;c$=wagM~q-UBf2?RSUL>zz#^wkh=zX zKaazt1qnO1N&rFu(?Om>^Qr*#O#R=61+?q0&e_%?95SSgNWnVD#X~9!aUv`! zxM-03i`v);SZZ&E)pmyjEX<=g;in4&&vV*hOg?3}4GkQ&{ppSr&wLhsC%#1-9cFk( z*?fjBs3myuiq5KjN8hB&94G%jPVHykhOV{q%OlC^SkylP@rKZjyO;hy*6r8Ul)w9{ z0dW>*xwNu^R|aKk{aSS+!|Qdkz@ONng(V zneAj2@3H{kK!3H4#^aJ!(L#r$ao)`UAH=sxSu=@u zu72YwmLWBM5Ev_T9R2^ewI7=12qAiBZ<9XEB#eNzu#*$b)f+Q`*0g3tOG$Y#{21Gx z%__seYGCuql|K4@|yvHy8v(`Ip832S-^Vuaq0i!_#BuJ=;Pe~XJ8UXI{C+4 z0mtw9L;z;GK0XlC&o=PY#g3dQTYX?LBCtlO)*_KgezX|7r=BbUado!LAag z^YIV(0WQNx>+)so@0WtYs!z(0jZf$a6x9k}EB+r<6#n|bQCHag!qaoPBb8PJ4E{zeND^r1Rx?yS|I0WY$8LR-R3{aPimHH zV8(7?uErPsnB<|`0vbCm#=9;6u#T9=gSn@=_;g@zPFZ400Pj<}ys^o*De!^H zenWH?7XUul7bkxgrML))qJvi%_NakWX~T9^8>%1ell>u+_@K!qb(^2L98m^TKZFyf zK|vEMZJyH+M_B4Gdap0V7wMf>tec2~@PC)hDik@&_KP;$Cea2*V1F}986BJkDtPNV z&i}(kHb1`==I29&HwEzQSx;>9Ip_%NAAOJQzm5K%s!PThv;}`0fjGb0NF;H(7!cSu z`JD%ehXQs0CiJuR%KjxzV&$dL} zNk-&Dy^|*9k>^labEGbSv7i;m({?4nI0;WG)d+C=2VSYvM`a?4Pv$=9r!h--nsD*3 znqy=&#B>SlrU9Mbh3X*fPgigcppjx->c`@jE`-G9ce$^bKa&x|G4ubj{o`+cb*%Dt zA2ncIT{z0vJ<)1mCcvZbc!n-CFa>f7&{+o^9KFQ*_c7}KF7g2F=yBJ8I~gi}I_VSV zX~}2emH|{5UfP)r@Xg>smnX^yI8)YnQwNglo+xE1WQj6I~Vv5_Z!$sNByc9M%Mn%7lGN$yS=sbUv9G+K*Bk#SIAzhKy(;laF814nz{!|wwyo(0T zee7p{C4}3%7hs5`cw4j1&2n51_A~AwlAROBp)XK+HZti}>{>jA76FFa50&7i!=VQ{fEKw;7VrEv@X@EoRvglCS0yD4M8XBvK zX|9MORsrroa2Eg{j|{!$ROn3M6{L;p$dnIFQ!2bWN?OCBTo9!91o#5MV=^V3A553w zPBd^>_J?dke#3eNr~U{-CSI0^u4D3%i%CK)5pqr=NkZ^yc*WbX`@V4-bSg|6WMH?+3^egKStxH8CMBmAS!4VaKoMcxhEu%1h561r~ zOj1YM7OAu#te+v3?H9e#(+<}D1^t)F{nP+GoJar9ZY(hZyP7VBxwH- z#4+-JUIt)j;beUl*YKM#pr zM#g6zEBv5B41{lW_<~>*O=MC6d)9#1(y0&H{xF*O6Y7)QA^HbHbR5F;8;{wk=vY7! zPowkKeT{Ssw$(KD{$I9#yzQ^vRQ?{22H0I?zWa&Ko?jl!&aC2ofB`;8A$^>kn&CM1 zf67hi*}x_mFpUFu>@o0Hp&WLc#Ki@GluCb8Eh#2}jkVKA(r`}Yc^-?XPJ>wRmdi@2G zw~fZAL+o($_8*q3Ozo_J$G-E&ekO!Fy%%5_Hv-~NcX+zpuFlPLEA#VN1@8@(g@Aq- zN2@od$$c}2NHA_=0cCOt`7&R8dy^ONtrZe;&gVhg(6QTMAZ3EGh2XUsT9O4^p#+j( z=`_W7h}h*M(#1##$S23^V$RbZgPwJGJ!x^mdRpfcY3vICkC{g}rEyp|@uv)Tr~ztn zTc8cyjvl8(z}=?(M^+R4QFfQKf^CGu^`n1{q?2OX%BC_Crrd@r#zUm6!|U}pB_N+1 zzZd`a>QXMbJZ1asgfO>HR8+2Kq7KLYvGNkQdkx_7e=l^qUFGz;FXaRoDynKNIf7a>sdaUB>FK|i!Pje`~HNly9ylo+{+XBEDrThsebwEs&FIQWVD|@79 zh{QRC^23;;`JPlpiW6ep20(SnLGrB(a8_RO0GnLOjK4{JR!@S-$&Av=?=|)scH%iy zL75n-fkU-FyvO`0?K*0{xD(*kM6B1MSPBWIr3vt)g0CGH|1aA=-u55aLrUb`YCw8) z8(+NZ=%->sxNn+of*C#c2{o!@e`m+$G3NcB3WAgpD83xJN+sH}lt6zSKlGABM-CMj zN~A0VMpaNwTsdpiMny3wjEdy3iKjGDTd8?KG2?cQw4B3?okxl*;axNk@4$uj+^!y{D&24U(^z>xjpD?^CKOzBZkLLJdTE7Y za>xagMoaOR>GaTK*?!d%Rg-Jja8X}Wx$7{eyPN*+HK-4Ow-}MwJm;|OudcWO zQ&`I!i#E?YuT^_=_PHA9h)Z!;$-%LxOiI=c8qnPm;&%q#pPA zvi;OiX@7UAVUH$L?K> zcRE7xZGm}lgQzv4Y75q1dg~aw3?oRY<6e6DA5uy#N^(;o?02Ea5bS)8Kek<8Yc^!lN`mO&y~BQ5{{v z{f3~|PwB+#NFlx=KcrA+-6sAq^#8K`<8A+KK2{?3UjxmZIyC#g_K@S+{|m}uGj4h8 zx&ROc(8=gvY zl%+`R>jf(WdiM|J2?2kJloUX~LylOsUo<0n%lq{~^?$L0)kX8r9^+$wk*NGRNDXK= z+<6b&&Nfwq_!2|Sm6-Wbzmv}I!VKo-S=rHVLD@6NHL z*pmjtVuxmb_>R2WN?i(dt5>0Zfy^%{xcHfp$tLvSp1Se53_ynKEMH){>XL5wa zJK+mtWfB@t3ni92Nc*!s`W|B%Db__C9SN}tL=ptEq!kh0HMF6O+L@7K%D|mdm`UYF z>i-aN`O<|<`0QUkw#`L`xRxXXJ1iky>P`jgp*i@7#nDEb%;2*q|J zX%128!7NYjxFR5d1OZ~ou^RjAF6;z_{$)yIvM|2dh^ngs^%c2Yu;ZjmBupPG(W)vez?0AoNDqrHG2B5ZRj;W}-2A_6e_}J*Pi$)Ak*x}j*8Z_ml)w>bK>Io?KVJQRgu2+> zc@#s6lb0nF3HFj^KjB$;N(-FV$sEFYcTz&9cRD9Rp^a7-?G zPGx>}O#NS4R<>UZOI?hc{d12ip@Y-F_Wtd4F(>WoIX*8V^US#Qe;2eEyV%+=&2`)k zZ%Qb#*q+Xr@xo|a6GGe=Kh{y0AVU$%eD?Z3?# zOTxpy5S|1aA==Jwy_j3q)e@I$k&?S!z;_X6xew>}1V%p%D+ zKzJO-f<3gXICn99$Cm?=`jS(6aE}I<-X&}{qYCF9aZ}x>Rq_8W&3Z>{;JRN_aHPdIXPLu z;jHo;0mSW11{CT5><=Ym3h#;`zu}iBLYP`9Ot*%I8c|&3~NYE zg7RnIG;p}~_q8hGA)~?>=ws?_Xq)?^I$lI*8UBLuIQoCtezokF+JE1ARmo_Z2Jp$i zY<70m@#)*&9GAz(tpDeNJCt0mbkuNcExhw*1brwGMs|mFK88AbUaki$L*}pmj>MFm z@246cl;NU6Mr17t*z>?f${4#LSO#vFj07$RK@o&Z_bu!vuYD8hm@ztB`@7fChr~0f zEp@Tzr|vU|xx!729MfD)DxLhAZ;rqJdt=M?kEQ*OS>HWY;$FLUja}Kh^CZrEo0VFv zn$8i@pkvtoy-{uuO&77AI~?!jHG#t=(v%H(tV;EUkM-M@H! z2>X3606TG?RedCcMJxsuFa}h!!SGc9ADfQTSP;i1w2j;QT;b@r#n#?B+{R+S20$AP zaZ}7^?+7La&B9_q=MSMOm;)R-{Ish5ay|@hNUb!Pl zS+`UAATI2TL`*Fc5z5!P#-?5hE3pSd!9h{0AT?(?Z%isZ+{ z|I7B%$YXAQ^|4yds!PVC6mbi9FZTmf zu^PgHf^2ivK**3Oyn$w#*-jNHeGv817%V+c%A~?^WcEy#(kZN2q_vTn z2=E~*Kg_tgY#?5mgtbyqpOGVqVK_IU1-Mn-FlCwANdt*@faJjKul@wXNxg1+F{HT; zVLu#*X_nHG;%iclEdy{o{J(6!*>XJXPhTp-L2IBo5yC`RTW@4bOCj4z769nn-q)pX zTf%YD_s6vVi@eZW7e^as$;wmvgB-PN|({i02T&Q1y{qNUR>h38-0GS*_m>^E46O-X4dPS3{|Wbq#|dD81=duxF~Q~q@hxPAhqCq(ZE=OE)sk(p{&7!WrP+) zMk;y6-05UP&v44m`LbLBBdKM8=2MW!t8J}?#`;F6cDJ;s{0^5Pmn5?U4?qJn-=W!` z@{3<_vNu?8^bc(NAuo3)r4a`(Ut*b-8KnB7x4+0z{^T0??SJzBygh{dz84_p4~TsezNeFp zcVwrqeow~}pCsOJLupBZB?o_v%v`hneSE7XHdG*5ze|&MGAA zc<^BfDHVSV0~!d8Ox`X5+jp=K*jxz}>#6EcBj*h-gRPxj>%$f}A-9D0G(^ECF0t`ZAMeunSA@FFIxekG7d&(Ju( zSHSUB!04mu*w=3V>V|J4S{U18Wv z?LfQGhB96py8W%eWpscVc*pmCpgA4FscM!j2FznwAN$>TI8ytoGZyEn-TgloA3FgU zn`$`Z{8=-&Y39MI@Z@gy1N?u#PRdHPIa#gE&WGycl$PA#8hWgVKul;6`5lEzvPXiq zD6_3KMFxek*3FfQI|0>NrC!A|q9$#^k0sM%6z2l>A;T5(isj4nUNvwFO(yml&23cK zQ8+6tS)T7P^9ZNu9V(6_MS9~u#KUpB#gXZD!X3oO2}hM3g|iZp<@p{nk8qmaq2fqV zq&NOUJRG-M9GPw>+(C?-a8%h*I4dDpp6@a92&d^CDvl&YdgDLD!*OMNs2X_nJHEMw zYv40sb#*dZS;3w;ZwSN`5O*F;oM=p>i}pNB`=@dgG?j|sFwbFmZ-AZ4I+`UNPUBrJ z0nA|1$07k+=R6A43rj&JC(eGptuaVc6cdPRYX*(;vW7Q4z~es`Q`Y0ohsB*vnHg_p zAb2r=1zE@zw1@^++xM}EnQ1f{FPWR04z&i~9a(7)XP<2Yms&Mizlg3=KJ=(I_mmNGu1(!9KELMuGT)*V^- zNgZB~#nvO0JJ~XLF@ObGq&lx#vi*nhNUqiu%V|9#i{eZQiYH-MZlYpYYonDg8I9iZ zgp1TM%m;X>Gp_@UQVv?N%4ITJjuId5_In%37#jF5{`X(|(GU*wUVspOGW&4l;fK_# zR#qxu87qPgt_kxznm51kmXoAYsN*5eaqfJ|A$BfvP}*^*ydvC{jSrF90fdW`y~_@v z_3&3;gxp65!tFCYHZV>PlEpl>dQ{LRzW7m2k!{=^xRrJBh(P3NMc7=19Pg^q*vMp4 zf*hS5F@_))f?YeptGgnGIov*7h{k_8p36`3k@8m{b4oro493adJS@eTx+}&o6z4>qt-|+e3IQ4%t+8+_vz&yR&-U?eiyKav> z3}GC_crXmbw|+$65B?zAdgPJiLAP_g+V6F7M_|KNN@M~RVQS|EHRz8jl$&-nN7DR} zkrgEXi#lG}4645J#@L2kP+5U00KfS9A2djbmXXl!j^iEZ4HQeEbAUC+lJj0X? z3;>Q%|HnWUYS_i#$h3mV|0*7R+vv*O?ra#RJGPC%0l_o9(++@8hYx-*+YDiKP_5m} zrlvb#YDyG?4Ry`8JD)7UL6Iv0IjBpi*Q*4PcRYz%Hs;whjkM;0Sn@dHrgT=5({a=` z9?AhqU|P#YIh==#->vFL zLb*SRe^{D0qltEmIAU<t z<|F1=N8|t2FWCo@dD1k)J}7wf1NVRS7r>ofFKl+Yq1)$$0PnFwF(+>;wTG_;p}%F> z%ygEWIFV)3xS^7#L2&^fwQ?Gk0IqtHWNAjSl46G9Ah!srNuFdO$Fgy1B53^ZpEB|Q zQZSMyT$C;^Dx{K4`WW&8M44n#JsXAGiF!RORO(^2i5EvnrSg0w%W+}E!{Ib0%;2%6 z@?YYI1j(~XsHlO%wm<4m?c+8SCxg+l*pKn&hCMdX$p+xADvU%Kw^iZ=nJSG;_;t;Ely4`@Q)u0 z#kr7V`X6}5duZazNcAdjau5d2Xk?u329SWkV@dS-Tvk-NICUNbK2*sdD{=vblU|=x z#l2OMYQ3_gA#7)^xm=94-pgptAW|*3o zaP2bQ?Z}xb?XA*jUI~xTKx#X;(Sh3Ed?IlTNQD~RFC`X~;>`c(w@Q+hRM?BC!vRM$ zknW$tpGXoalc< z`n}d*YcmWwoq!$`*N*6*u*MnZs>jh zlE^htDb011vXO{+#?>R@Qyj-gU!}`SOKnMJ&xPjm7kDY4l5yeg`V?KJ`i5SI^euXJ6PeOUZy=&0w|^p4+L98!I}PAT zFltsjWiEsU2J`ve=2~bkT@AhU)qa?stjZ1m`#0wsQi?6yAch#*{-5z=w$g#%&#kO< z|K`fI^&4yJ{Cqvw~=bk5t@@IcEu(-Hb`ShnhZG9CpKZbm8ZuK@+Lg(g{(BE3; z%VO{Wv8>dD9I5#byOsOIjbhl|Fru2SLj6&lO>)><$P!a<|<<@^lfRM z)WcjgmfjP@G!UTBaa~A-k4xe_HJ`PyjtMAj4)2VZsqwPV&^-W5JI>)WMs^Ium*LJd zU}t29XMghqox#~-VCLu@(Q_T6jbcjwtdZtxLKUrlJp5l|HviWXgClM~Er2nF*BN=W zvDWWqGtg<=aT*Ia zH{)OK@zRK{sj%*gYtb*Gm z4AhAqDFermCdGT2aT#t;17_MGnUX*CDMgx2+fyv>d5pb` z<48LMi=2N~+m9QuFqHBfBFh@MLuamDtDKll zA;L1T4;r}dzWZ|JE-v!PfQ4*xvlTG;S1L8!K_^$lN44?Prl{>H~XHjf3snXtS(o8f5y z*)hj^<4M5DpXY&MYe}o!#YUiTA4qLxCf+yudmYMmkNscz5YGIutKFTP!!a8M)hY{* zIymwBS)T6%el!4E=>AP2)<9uBCNW|CA%Gx=VZ5Qz zY=u)s!Wrd+IN!3A`VuqP!RVYZzc z1U~UIW@(QJr)eZjU_xcsvj&EIA+f8gbHD9Re)NO9-rTn+bo7}-mWV5~%1Jzy^6|%r zts;q1csN^9QV+dKf&yB1E+erioy!)BS!qU|Cn(e{?e;j*<-CW=P*!6)#3zCXKhmCIzWJmm#l*ssK1Y!+ILdZji!8$Ms348Om$G5F~DtApP^f4;NT?cm%a^rmsM zQ>$95W2X*nG9{WEo*eu3Q(hB2Z9xiKlgelxH84MqI{+-a_{A@tul2Jt+0xQ1J{kbe z!e+TW<>q#9e-c~mr~gxiUFrf=La`7!YE#&t zh~h}aBKWZan$KTtHnW5RMYiz~5*3ouIB9Wk@rE4}Pm3&hf~-l$4M$G?%)v$mo^r$^ z6pOX$+yjk?t>?N}4JbQilO|mN6eoY-VRR`hf|EfRcGZCEEfPB7!0fLTr~{x@)+7EX zz6yx>v>;-4UnTzk*?ZF<$*${6?7rM8v$EFiu3pfMMuQ*$5)d(51PIWG#terehb&D{ z;g|?}Y)3dOh5snR;b3@dDI5xt4%wrS$q}iMG^8{nCCj6ctPzI`#0`W*Nfbbe009CZ zh+fc3Rdv_CZ@K65_nmXk%bVF*y;fIMch{|YdAD=7v)ps;efPbm3Bqe)KC+Zn=HU_X zDUy5{-|i0n*Di1S_`TdIQnB%$2YL$FQA}gyzmd(mH=-W*g_))LpPwJCotc~E%}gF> z;?=-oyZE*jZ`55TS_!$3b#3y$L*vIdu8IDHyBpm<{2#w}+__tK763SnYPFhDACY2j zZ*R0w9)cl|kJr|rFY)LJx6TQ1o6ZH~8|glN>o5Z9QJP|*Qx-FIX0y2YNqVO-ASL)y zs#FrmgG83G#W0WW1}LIZVr~em0HFu)8Em_OVI31d{HQE@Lx71AOy(s^5T7;4Ky+ zkA&BxsMg_&vV_znKguAUJ+&Q4w=oi0nOHLA$MR6&oiu*M5AlojM2zz{&8Ud`{^{NU zH`a*UbF1s_FBdP>zcMjZnO|Du4ggmxJgvp6h6rqd6khC2e0dxr07r5P4U{Gf>H%P% zNzXf#|J_Z0>+7Ds6&L`|V6m^;{j3jr*#oIs?GRoJ#7_u%WjqnMkjfRxnf_r|Piv`I-W$Zp zFp)}mHjg4`PAf>N5fz-Qz6iwGQKn2QB?*$jAs|&UWH>stvVcyF2q9fsXA3-8MBrAN zBJfBthn59KnnYjYxQ4eLW->kQ=8rK2=U)>B zfHP9eP`4fQM{{h(J8NAGN^+NF2$*tHm`XU~H3OA8P$yMSdwD`=9SpG^mRDc05VRf; z;?5aAaUn8HUq*)U^RYk7M?HA#uZFG5AL1C`Hx`%N7sfBuzCSZvc6E8lx$FR-h$w&f zRXnjutl{sYW0X3QM=@kt*-l z@ninLQ1KKW1r0lGJs9o)Cff*~>z=_g|F70l?&+y%_w}*y+PQ@}p2Oi6PHGUYI#zD= zdb7zmuL|PO|7nx}F58JDjRg3=X8GTZ^vCe_+!kVh%718hIFU)r?tL&aN1Ch4uDLW1 zZmZ!9R7eFxOV(Q*Xr+Y`yxZiTUpwIAwJ}!d4OhX!JlFwX$9b9Zw|L@jY5-LDEoJX! zmln!U_Y3(#-)eebcrXPEzK&D$u*_Le;(*6wT9rhYN}Us)Kwz>=r~*JSdZp@Z^tjz*GuvyGdcK&{?sv3Rq=LH?gB84 zhCvx$cf+SWGOe4rNQCR8Ra@faw76XUwT@j!e;LPJ_4B^Zyx+N7dKSPfE-nJ4AB{h< zw6v5k4z>jPo7M6_b>@<*PF-~PG_H$^xKlv06_fexI3d73iFvM}1Z!YnW5X?$N_?3H z$J1#ASUmJM-x3HB_vXaJ`cwN4PZzS8rMS0n%<=T#I@-|rPqBvtmUtgMwzqYVid1H3A z;_zK^6ytWLU9ts$IDLHEO)P?qbS6{CWwR9s9=fgb3TcA&Zdm@edi=^h;0IRBnaTH4 z`Ne)^zF?<`DuQYM{rrcLdv0qn5P#&uAI8x?=YAF6zr*r(f3s4~SC{5ob!8DJ#2Zka zcv~FatE2M}i2~r;LH@x*aNry+Q&aM>fH}PWaDE+k@YMhyC-Mpv{$=4!w*;1#@$kHN zufG0zx%||T#b&W@EgryYmtg=z{3wA;eFjCJ*n<=45=uAEmin> zIMT#v8k3ytd(Ls{y+q=a@qxHfQE)ZXbcdh z^O8D!deE{Z@A=&^Ks1`u@OIFjEwzXg^uZG88_x-!E2qiaZQT_XNFpqt5vjvk=u&rB z#L7sT!ro5f7c|L_4n$@J+%L=lXZRRLlYY->Vxf;(16aa|)4ocqmF@EgV2J`}Wwekg z^#IoD)SB^Y@JwJ>%P}U->bAJ}VSQ~Gdy%cdfMET<<;wwhZER%Yav7=%$tK^@PDnc> z2&XTDJ>N2!&#*jwU<10vo$*ER&kh5(-yiCls$v=HQp#fv2I z2`gbAPr^Q(adE^t9P4ST3yX~~F0jdu6lwLt*THP|&%j{*p_Zo0l~!DCbupExR%j53 zq6d(z^iAu2J z5|lsp`9=9-^5V*$%HQ_?P3eo`M;@QqU4sFzj@O^bJpn^K(vzUk32EL*)>Y+yE5^?T zt$o%P@=r%zGWQ6K??1~jPS`zn>o73n+yP+uK)kw|iK;c1!u=_HEC872H+AIZozNkq zUqV-1X}4%(p&gZfU4GM8$lzE&rB;i_mRCyWR+cGWRQh!6X?U42z%&U{k#%*`)6)bJ zMOXREAFNN+>QjwE?-I^g$_{`S0JNg`Pe?f8Q7(}Q$^z1451y8j{D~o+z(`rn92f<| zfR!*KiCA%NMm93|N2hRXi(o!ovm{@B*cT}%byHtxvaeWr2gK1>iYgoUj#RmDe?B)1 zAf6+o(x)@!Pd^NsF<^#(0OQAa#^QVaRWKlQ-2wWuTgq!7neZ(=;VkkM=}2A{AaEGD zOnBG$NQMP?;akspQr`Fu@T^3*P&ilkbl31d`+u|Jr+o1e#9@qh-Ve9aGA`dY=;jK8 z?k~%+`}C!m#_ygwQ+{RQVhL{;v2A@>SpJYh5k>X|4jzS-K{}#U z{v}BukjiY%h#pMJaL!d&E8u-jz=W2<_|Za$G8t04Djv=kGLP)rzwh;GyfU%2GRxv9!CL~hLl7DSW(=@WGYEV)tUE!|d%?{xu(R|B z#e}86M#30mr@)b)l{NL(xEDSE39FtjC1deC+LmXfS+$0D3IC(x><@=?W8=rmpy4VJIizdnkW z102IqL5CdytvZdVTR7@Q`G0HaFPw}jlj-G3`i~>P%QpDhjbMg3A)!uP1!y#!(6w$Z9EfKaFYGJc zM2^AW3(`@4vEYtH`OL^#DGdXFW9F?EzNgHT{boL4d4-N~8Eu%j7rqPwJ4S!>L}^C8 z5J#mf7OiFp)A>B{46ZE$btI&}t@vLDiQnrSzhH^7#&THw^ZVOHZ2x1+-mT>O+-uE@ z`~N0p>R-ArR-0U22=DpVA!mGo$+rJHZvjy0+s=R)0K6Trn!{TKa2}ur13>y~lwj{E z@9?i%{#ioGUFZ1OB#Qbj1ap`6OlGeep8upndp}!&f#b)IyVqZTU8;IF7I9d;9ZpxP zN17{8{`g>kIP3;1J%y&XmHdnLq9O*f)$r=g3Qh&2@_3Ji@--y0t06$6fP>{F2EwKX z0ttj|l&Flu6Le<}_0}5o{2cD1Y~aRUFO{R0Ay!7mxj|~SUrp9u17e60R@d}iqsPAFu`KY`jDii-uHbs)wa0IuQt^F8iRw%8c#l}AWy zwQqjsE&$WXJ%(`e+Zx-8TonU;CKY0CKm9$g373Rn>4~t444{*Xz`-;g4N7#OB`9oX z31LT%j9tY4;h4j)jm!@t8I7tp3 zl-9Yz=ly=JIQRzhDwRLNruaFrg!lg$wpD*<0Ic;CdJFknPc_o7djTwQriqzw{qi4< zISg+$e&6h^qJJ`~y}(Uj051oKO!>2-AIBR4F<~Ep;vaC+)6Oj{VA~h^i!ZqWV+w!o z0{VyjPz1E}o8%!8vr@wIRKQd`B`nmJu$!^2&+Ln0M>2~rY%6}-0kC}WuVet=HHws9 zb5CNnKZ!Xj1;1E@;NP#Bq^01SGo9P_he_+l!ws6^|PA}oU)0I>u6vpILTr{Hjq ziHcnmKk~)5ID9h%42Hg4Y|btOB}|_#>AXhwemw?+mOxd4ALWs4qJPMbs?l`|%l8T% z>4_iDYksw9yvHKq)Vuxo{~E^6k@Fv8rZ0%#(?FDx0#5s{rwi`oQp0^^VJZId%xv|C zb2Al898~nS`jHy09ssuv@VGM)ID1H+7*1#;-9z*` z~M}n*c>d**$3Qo+sp;*IF%4wRDx_SW1kH^$81-d(nmVuW*9I`xXqsqKxUgU zQ2oyL8XNV-LMq=k-*fP2Gdp~MAke0X!N4hzXjI>Xl*$(uCljBqP@2yiizhH1mbF`5 zTCuM~^Jyt@j?%g@8o&xX+o994Y(PMCGP888N+&mBqJRyQ0e(}sR+ae%NqFx9-iNsP zp}^1x0GMx&p*?r47}#<8OGn8c43JawSA2^a9|{nDunQN$Ng*j0l=X4tX^yh91-iszNUt{=KW9V=84mK{@Ju5v;F;?EnH1iu(ihF=``uq*bN|y5Q}Jit zJX`(Y)Iv|r5m6&5? zip+oe$;QU-{@#i!_AjMI4%btI!#TG+2b%(o=0qp}3YE+f-m#$EvY>B?VHo3+4G(F> z*CB-f1YgRq!X(UeMl_88vM!LiS(gO-PkUb!#MdfJhFcUL zj?DmI+%8Kq1HgQ?9$wOYX?O2uQw#|Gh$+xOc!e00xOzrwL8gbZw40~D)GE~p^T4XvC#8)w|+{Lvc^$j3|UB5PbMAV zp+DEi_P8@q&ONiR*7*GRWc`Ip7wdS}50yPHD(ZSYj`1;5T$*NE|K@X*Z^nQqdBp7& z0P|Qbf$19@+|bsym5zW(>$ z*@q9rzs0StjWm`P@v7T(S@x!>W^K+P^e&+Pwa$OOs}5rz14k>BvYT3~N6YZxMA0LI zzODE}zs(S!^12q6cK`lQ>htRx3pji*-|X+N;#~n+j`!2WnIIwp#LC>kp7Js$aZ8|Y zWqg`=YIj*dorA0lD?*tds`)-0UeYd;5J~=|49jX^{^}7%-r2-9BMg9ic|CnRlNuVx z^}uL!JvCkFnZh?;jf2*0fKCH|E$_MO!hk2Jc-u#RaDe9#cDADrJ}SdtSV0po@}Ytl z51UU|jKP<&YFqVaDXqxL_%!i$cKn8}^}PWyWM-D1yx`&PN>e*e;J z^LI|2t$cU%{05Xi5At#Lq2lKEMs39}+xbZ23V+34_SoNMzQNHj5aXbKXsC<>ft@=5 z$Zqdy5>HT^NWUKvdKSpP(15hkn&ej_o_?AlU`$VFD(Sa?{?^`}f5R9c|L)tj&p5!n z?Xk!9W8!`=nwdH5X0c$!`8K@Yrj5Y6hW^r#c79ZLO@;%!_&Ea}-f=H)vYW#b4rgX( zquEt?r;i!{IJ5^~yUYM!JPhOb?zK58zv^F|J~Q!ffB&UiUvDMCJvyGLNGxy~=GJ#~ zj@=BqEzS78Crye46Rg{PAp=8os2=%2MQv$vKTpep@KQ|R*#OHR#p+^!FtGN?BQ*LI zw*ccSqO16XP#!0nAKt%j@bP+T8K}uc6r4;eQCP!?dh3H zse&hjbcN4JrHT^W9`z$kc+%fi{NWCO84yh4#hnBi6ue4(gF_X(AV`D}@z9ApGa;dg z8tuweo(@s~;ZFItbi=pB>F)^rr2}{TPyNOJbHcf8I1A9*+Z*B0K+e(RPgji6Lzv9p z7R@glPR-8Z<~i64r|GE)ln3Ys+~9*d!V7F00%g5vlY0&ZPSP-c04C1hRmTlXC3E;r zz?u2^+S0}v@6EF~4+e1jru;*rz{2$HOaX%3o%H3&haM86;a~lu_f3}zg-JIwRB^q% z5E#_K+X0*sIe9>NQ{aeO6HcGbj*BpIfId&^W;*^A->e6n(qCqa=GGMnawMItcsQRg z=~7vOIu6GA!M;d;B$r{y#Sb!oNmh^V3F9yYzioQ_z(M!G$iZADm*bepNHhlQvUun- z%)!&AW7u36wzNGzz<|(nhv-jUGaeH{3GW7cBcwzRm4C=bWIpnXj6nIAhJZPiweo75 zl2^$R@`pSEYdPaXChQFVqvh84DF^5u9p5+JgSV&+<8{9S*<4h?TmN3h_kKS+wNU@$ z>9eJ0#xIrvL!gdrNgf2GA&@9=#HrxT2(XnscLf->`~PMbaMyqr;b{z5J+iw{=q(O(5JI&3cgZR2O59j1RcxV`X=V*sC@1ZmabsriAZ>5jRTWf#xP zxVQus!=tQ}#FAg@WJmM_uzZp6Mg5@Db(Rg)#LZgyXyLy{=!AV zhu}i;n{uO&kVF*Tq%Ue)ei#$hLqOocO~_927=gPz_}|8FzV;jkr7`kiI_r8cxtwpr z?r)YW?wRHJ+E>RXDyyrA=w!mx1{FUZ`-|y^O50ZYrqE5nGu@Ov;mtq@cK}#F>!#0o zE4Up{%fJ8-njpbDjSBXG@f(o;WZb0tE}*{+Y|p=O46NgWInRCfyNR)gHv=AvYt<1x z2~fFs-Ze`bacXD~yhBYv;m7|jp}#CFu0j8i@%e-fpKGh(ogC#tt-cneC@(YsLPbvl zz%I&^g%cQA*&}09hZh7<5`imq)nd;EzRWzI?&*ag)q~SN{^JXr`4pYv6Pg{Bg1)rK z7$-}_C5Zr`v+|N=g&6T+gEcr-L`P5RLcrH49)GN;rF);nBpY?0>o5{iSmQL^aHHx5 z@Fp_-n3=5V`8|d#sv)lIGUac6Hv@o8n3JX~vgdDt0bq%UQs)UL2}VSpWpGeCv8vCeAD8ImT&bm%#u`}WmOpu?l%4x#z&_(a_UcR|L5W73%#z2XZ}xCn(pbj zMfc}3Gu7AT=gT-sEeHMpnJ9mRZQ?P7Zholr8K&ZAo~0WcmA}6qPywO}SHs7^WX8|28AQwygnknUhv)c+>zNV74AakX}4`7|moe`FgH6 zhz~FDb-}EY4%p;2r*s59XB8`H`HUwplE_gjl>Ze^W+aXt#<_$&EIk3>VhaVejITi3 zlOBkffn?TAFu;YNNm$##djRn^a=Z^Ax3=hd*A_B;aRUcQ9d?jl8C-rVfQp~E>%64H zNbmHKwC6U(z)sVj{78lnzC>92qiMn@&qj769hZ?jJ2M+N3D)9A52 z2{93IA7(1j#kH@b&MsO2Y{Ql;W)akT`}&%A-!SD0P7ut1ppHMG(_A7n;3xnja2>do`gRHZ z!*T3|uO9<^Pw>f;CzFC$(w#`HuD>Imoa~Pl7Qh1#Pk#QkjfcQ7yM+FpM>n1S63$1D z`Psl4R^l@_5jeHJ;mVZEc13S;)ai#tz^0D~url^X{FRlJr0thpe|_Qc;e(@veZ!0K z!Gj0g^cc?gK(29uNMsI$SkezhQH|14flo9uo}fv^4EucX1Pxl3)~k@rGdKjLA=c-M ziuEAkkD3Xm%L9cYxTG-vr+w0r1O-AdHK(GZgM*pJTz>z#dc1gUVP2O1SS@9+e6m9U z<}=SOGX#>ZNF#ecSH!@spg$PM`XRhUegYNS(l81mY?9$eMmWopGKjRrk!a~GvLpQ8 zYFN4pV+Utp8m<7P&sYB~VR!4b^|JfQ(qi+A(+lOZGgDN|oII$MMft-w#m_ub=2YyA z+jf8{{4mb2!7-m@StrZcHUJeqFPorj;%ep!1-#D8>wf^WIUxF`<$ssZzinK5k?Y35 z8*jWpu@g}PQ*h`1{%Cde!PMlGbJI8x$miL4B9IJ2np4O{&~G34CsMdr;q!s(^_n}s zy5P>@zFnotZ*e56f0Lcfe3P*&zb254!Nv3Q^Q@eT&i%$mKRQ3(Y>qYd?_YK!2VIoM zxeM$70HMSp7t@?W0iUQ|783^xjP-B;)X@_58A;g7vn1=!<@GR~b+xG70#7Q^d~Jt| zI}f6LlMZr{mSpp54d4aH9T^yM4;(ri?du=Vroc8Z08HtdZ@U293;=e`u2$#vLftVC z@B(RJv{K+(Pk+!{`9OGAR`iS~-B4ch2maV8QkKq_(+HDUc6aeVgaqRNO2OCc9A*UE z0;tE?W*y)AO-E_G?(agj=$^(Ge*f*neB*OxFHreYK~p))h2b(z#Z5(Sd;NB_pAYqS ze)reD0ZgCy1{>ZFupNPJMu1IRqV=;`ywf$H2f}nhpM*%7)*{+<$iLB1X}7cV_ruup zt`h@4|MNc|jgOBf?C@RZMldno>(*BL8yCl1V;V*P?tn$vOu{#uYowXmME)_qpu-}{ zcw<-ARiSpz%`dng&CJwYqehuA#cuLrMz!sxS-Qbq^|?U7&)nP`5ycg*bKiV+`C=SR zG>3tPjW$Iv7shETt%xqVi*L^IJIytj(`sR$JJYrPrw*B;KX&%iyfS z7OZ?gfXV$hX|b;-*T5^$*cDOu7@H~jZhpA>XV`{7-@*v)xhrD8)8eWK^KkSoqbn1A ze%RJ!aF*Ex*0MVNgtxA>Ot-#RS@Xk2eA-rypJoeJI+RNsCFT}ZJc!3%2JuC(CZ6|u zJ?e3PG`m#)%WD^1PpY=8r}IFDmZP5TH^w1t0omD45cx0l~`* z3$Fab)xS+nHi;$JOJ(@^?(SH*jIK#3)E>CY;4IJM+@e?VZ#n(1)c9?kcl0y={KuWU z#b*H$4E^lS{%jkwJm}ngn3Rvy@S%Y61h;H=%m3%)OH14%|G-G?MY zrU92p=b|{Bck|U|Wu{!Bj8WmU2Fg+>R~8QaMBccf-ORBv>C4*MT0Al`f|o4JG9JG) zuy5w4274z`c%F_E4W1L!_wMv#K3N#Kl((DYjv#^q&jV-BjjVoOCokiOL*4aH5oWe)P z3)!AHU+9Z2VG8&zw*Q}5o~nQ8;$(S#ae<1NlLRLcZq-+D`^&cM$@^5|wj)5_i~<@4 zjGNLYtZn}@o#m{&)QdQMTdCN@MA_iPL}y`%;{^en3OXHAI7_s-Bo3ZR!X82k1oK8H z|9}B}&`K+~o%C-T%wFW0G4RMEk0b>9i?2OBSaj~;s9L+PK5@yFXC~xZ7E!JUK1%VZ zud>E2q<=DpbkTq8G<-qs8}jmovF|HCHhCszU+EYkL4@G8OIugkk235pX2~AVDap zz-I;FB<=K}1Eor%d@jWl}lY?~7x5X`BDpx5fcW;D#-)|87_2qM)Agb$&; zps6q?NDivd$`nq+gp)W9S@6ho3g0Rn+^D7>%%w*jDD{V_?^D(5SS4_ zpYT#Gd~=;~OTUYKqQsnr1xZOV0!cW8Q>yD0nWcvaZ!gq}X^6jx9m?XG(5gt%d?{gQ zZK1ca>U1LdMCo9Uo=Uj%!vV?>T|XOK%;=ln~I#iDSgImN5BjK%QHAD!#Y?$eKRh)O-3YW zD9TAZmF8|hcXwyezxx>XQm>AI{lmkYbIHH%{ttX$02A`tqsgiJqRB}Yuj0%+&H+TS zz|*=!#!P;hqzRg7zh-sr9{Gn6F9xhD!6;tH~SR^b?c zZH0SAwJPqF;{Cz*9~g0OX{2*!M=wC(%NK+;Q~Wdlx+#D5V9#xi0a6ivLIM0L4a7j- zcKR!;2!9BxpwnOu2}+{!3Zc9V`d%9|A&OxLo9b|+0E1SY=UFMoG-QAuw|M;ME87%9 z7QD=p{=ImQUmDNyF5okNuR!F#IWz0NGB#d&V|E5Y8;fE_8E*gMTybp5pNgD{n~I#u zopCCAQ~2Es0K!=r!t=6S1Y7mnxF!GEft{p(GOE46bz=YuUMY)`gPHsQBKOCO3;W}#Nf)hcG*Y>qG#H7i ze+r%VcNhJyHvhqx$Nojcd-%}?jQY8HEn1J0GkxUrP^K(Qd9#aYb`k!H=K;Lvh+qOX zap`aV*&mnYmzOU#^Tmnup?h3K}rtzaDUmgK$_oM0@Cc0kC7-<;gXYfYQ|F~Rg{?@ti>gP_KF1;~3 z4P_luxl>{Dncp&$f4H*emOk(AcRTQBU;MFyfQ0FG@Q?K+Z6Hh|zzhLfmDq$tpF^+< zL3MbF8|J+Y&r(}H3*4;y?*{s}Msz2I{_&6BRaG~dLB0`LesZ!3Ah^RU8tNZJj&K%Q>7mPoK~Tre>OcD-DSI0En{9(kNt zU1c)m$aVwF*tT7O&<~9QDMuxCB}X8`n1$2sL;uVAE06!wx#Ri5Xl7)j5e*Kdqp5Mu zL6l0^1x*@Uo75}V);z1x{I(Kdd4>rTI;%(1wP}M3$_B-{HpAf|g9xS%Od^046n^i) ziv;(@eDXm)ULwjL$=rXT5x}1*%kwMM(=)Sp$0uHdp<9IE7Cl$)jML|;-W0j*05IL| z`J2%|IOc~t0IY*?`rQ;iCm~b(<|CxqLB(YZz;K9H&UXR*~*9Q)6Ecd|b;s=wd@OfjBiau2Qru><1Mu6eTn(6cby61p_ z-A8}pAoya$3NItVxR4B-)WK_>cdVqq8t*BuCfwIf^ey0jStgTbxgUzg@ltFkW{jokzxHEFp9kKpBE{^nyw*!!$I75p&e&mQ44d4Ief4N-m z?Onm=0~=8ex>2f2z)(=bIs*O*fKT^u@MPD3%`hx5EngBXjpmPqy)Q_SR4JUa$?CMM zhBW5e^hupD?FU*QpWtfLt1gEp1KwKf-S^Zz_Z)HA9y|-F${!OajRCtoV8(zM0HF~; zrc0R9H@)Wt7}#y}5BWy=#$|!H7Wa|wEKLQ|M};qgJS1x={xUthG@K5=%e@@HcgH|EM^+m@$d<~@II|C{nQ#ooF7Z`=L0 z{ZHT0Z2RAgfo?_sS0}a$5Gwx;L;&gronkgYMo^1jCy6Wmlc?e@i6U2MYTeQdNegJL zHL@+MTf<2-p)boDG=1%*rfFPSkm3s0(ILs+`?)#>CMPGO91gmgL+H3$TmLaPI+}Nv zELEPn^N}L{YWjhJ(Yz3=rg(6k_`YfYj}}LG3^N;v*84sHk6NB6}}8XwO9Zy zHG0cX^OF`TI2r{@EA_Sm!?~a889Z>VQk%OlH$&x~Nk^$%BW}ix^K?SHNJ3ZvOGF7O@(h0fhlCBaiwl6b{Yp%;EdbqpFZQJ;0=aw zEXz3ad9mKk6+hdQNyhs`UFU_Q%Va`v&YUYdB?VxT01$uE^3T>;q59gF?V|sc$9o&* zKDPR?f9~9Nodx*QKmF5~7ZLTTI4)pveyF*+a-w$jl&hXQ11_yPKE@7b)NQejP`yJJ zC{zntO74QW0K%W<`8#xXHP`D_3Mo7yh!-L|d6O^C0+_thH=`gl#4U}!83kAWhA_u( zu7U0TwNgnC$h7fd;lknmp&u0X9Xc2vI9zPZTy)KP4R74Vy9_Urai*wofM3}NMHQ;K zbst3P#g7+2Mui$dE?ZT{x{wi0iIS0Y4*6n3Xl*igdfJ9lDUzf`59QlNU37mjqpFw5!Ofv#+DTx`*Zl# zZ#Jsq-v7x|-u=zWdi?a{bp841>FV-2UI3tqn&6#}{ZX0oqGG3lr}Ae!GzKhgh5~&n z!*aaL*f2kwV9Xd`*X=?u8A>=LreBXErng-Fr9(SN|LZ}(-3CgU2M}zs#CZ7y?j?-yw24k71 zR-=k?KV{5h&iv3A2*Z|da+y3@AZ=dd2Z#R~@%qLF3sb4ZFU-zNto7ti#UqCnQU?#Y z2yfW~qKQL}L&l<0DSze9(l}2NPIe8Fu)uJ(<&bUIoKx{9LaAvIR}CR06rQzdDGz0B zupM8gL11!!lBZ)aH#x=BVKKT zL7Xm3)0DgPSLy0`L8xi8QYt32*+%-K<$z~|+sGf}Cpe$0;e?koNBD?vr{9^6`R<|I1_(*Vz&01r_PkWc44#xlubLwZ7M&0%gU&HC0x zf2m~e=bA7;<^Lnumh)q?9x&^ptue8o=EU{ZU@}B)`%_R?9s|^buDN*452M&5bS0yEkU0V>}g* zC~^Rr%ym=v%rjV#2gJpv;<^?`U}DNua|uEKnS-c8>w%X(|(0X|mxb0R=%iMGBAt zD{!n_Iw9rsM6mwjrEPS(nh1f z3D9l_n9tn+;xjY?SZjE(d)g8LdroK|G~QM82VsQIl=HaEB+c|E;4owWOxVm56>-mi zQUGO)AI10eB=ub@|F@n&p0o_o6=_;jE71;Y|ADf4z=54gX9Dq4BxEta-=f9rSgxS z?F9XA79n?Ad43_#+|U2vpY&q#eb`M*y*(Nob8cZ#7Nq!)9k`L~s1647)#rbJ?gafe z(|=U{>{1UN^IeBdIz6}4_};{Pc}-=VgEQF+m49d0i~#dl?wSq++8oACIRE)zD!Hcn z;uq!@E0yWESghe-AWbGrIk*Ktz%CA$msIr;CYI@Zx&)CFG{^~7K!P7h@IQWv#z?fT z0GLG)^%v{JMdC{{j9c>pBMH6?^6*$SKFQd0wR*!H?Ca0G@4gd_vmB_LzSHQ24Bzw!<0XXUuq z1*Ro!v1Mu9_f0bhC2(5a=K;{1=RJXuDmYlWV2n&+b&^4Y!RJ9*BkaJrJTeA*i>_K2 zh+eK|+#k=cx!*oFUU~Y=nG%#gm9t%CfZ9sm6ny7_zwn@6c-W7J{=x%)+y!7AW(0BwkEt-IsszqRPu$=aU!*9YF|+;*G=IC0`c^h>|=OW?DQ#vidE zKjL!7G4np$oSEvcojK(iGt-R-N9kQA3kid+f;gu7at9%Vij<)TCbj8S%FZ> zJH1T^LkoaHYFC)vW(@%5y6y=8o_NHE$N3#bb@4{6wvOkMI8$I?AOT;>jBtVz4%A;P z%dq+iA$gLHEapi`;!+VPuoAX<430jXrYp3j=&vU_>b7#WxU0PpTx%63D%thcu5Ft;^EXzcT-GACMPc{fE7&xEJ5I8pP&)G2a_4cW<7ne*fZlS)OUZRscYF$rb=wpysAk5LyOi9oSxfH{Y~>XaQ_y1=w;V zv;r8Wvq5U?mi#Jy6A~nCTuuwZDDD*q5C~i@|AZmUWe(a_`fI=Tey@yy6DLl%U;M>i zOi2FUJ^4fqAA5ZmrH{mH^&09c3^TD=|e9cQ^evng2Kk;6z{@2Ea!D zKDSXEG^KAcXK~7+DSVU5PT$IiY$lrg$|#pyl@_2A20&b|^CJbWd3s}Q?$HDLe=t}a zcqF&);9$JAmTlt5GM{BoC7#d;;1)JN(e^>}I>8E|u-^(u=wmbuLG;f0f!frNlaa_| zLm1nUQ23;j7PgACUS$c^<7X;`_VwYx3+6Pz*c!O6TH;rekKuFF{GtjcM=F22 zCqUl}0Qxinc##0Cn3wh4ny@rv-IdPcL-DQ{AjW|xrTLD~pZ&O;Fv=xLI9-V%CG0q| zT5-+r!_$HJTCH|Tylnie*>kYm)WX4(D37H>0gpMC(pmQ-u-sqGuQk4mlYig6bg5CU z;CTSu2B5`{V>`+IzwO~u`BQn5U#Zx6F>cFz=7;H_(zm*~&A^GpRuwj>*u=webY4gj z$Mjp}yc|pQXh*2#X`-HwSo?%AAfQ@;_-&Ve0&9*H(-fPYkt<`m74#2V+zWTdz{3we z?B4zEcPFI%^>2OaK1{?v;T9L~t6w;a(}0(F^E^u9O|M*(axNi_;cf%^YfokVV}Bw0 z_}Uka{4}Et^!^f5%6tmD8c4-Af=vEQ=~F(#u*FSY%}vcLJ_ zcc;gPhM#NRbNrReeQ$M{;r#@FY0yw@myii17!Knqfvk&0nx~OO{SV|jgxAz04M+;Y zg!EIVRS}kDE?d{MFvp;+cJT?o+ef(KxV+Kq+gNdL%cc6?J2G-4n@ZaY1Iz%h`vZ25 zzzhK5*LDLKX0_pk=w0m+I_x(3dp=R(gcL&%Z`v%=&e!zVjZ}$Dn5c*ai)P&Pl~46Z$egz^4ntnzHr3CeJ#5Y@z&jrJJYvR?}aQ z70iWOkET1T#;<<$tN1oeYwbGNlfOUJbnlJMj~;LrMzP;jb`f3-&`HDVng2V>O8i#S zpY^vpNx?JeE(<-hTrRs)^Yd($?^tY6~8RzCxMomu5r}8&hHQBtTLjmnwLX3|G zz@tLTT>8I$edX2FjdQjABeU+Fdz|a*g8@**=%G42qweJ z(m4P6Tp*#gcpUflC*~V}a_&N9 zY;Gn|#@z0=Eq}DuZOcF0;-^v2dD%_?SN`GZ-`b$kw^apwn?yPlKC+V0wQ#}ITj%Zw z`V&1e)!aHfZC}kFTt16QZ#&KcBxCyIr#?kq1oy=$tiT>{<v`?xF%7 z7yyR7oC%jgHjQ^S=T*xwU)o?htxM)0O_3%D0@o_xVXt*AU}3Lz7;HJ2>u?SLr`2+~ zo@lLBcW35i-8sAr1kHsqX{&sb*)VQlgJXv1gRb^^ll0W=19g~mYG1!UdbE<^^y zNqiU3-}=(lFCkaR+wIG^cG%W}Buuw@6UtNiX%JxB56lzy!SF2LlW669pL-c^r~J&+ zLj7N#IahvqbbMoeV}q-6QPil1$NxLO{1fg1aCIN<0$8})YyU!{z}hf_z*ZMFnb7Yx zp(I1v&Oi&FTPy!oFMSK^xVDb|?e%Ua)^5+XKKQ{8O2@zPr7sB)X7OAgWad4Mg}EbT zycwuGdX^svz&QYJnN$9N;ecErzBL^Fw$J|tOW(qZwV*;&9_F>fUS0k-Ei3aMT7#bF z)9M*K2fUi=i%+kW%hRho49K%TGBQ*8^i5995Azr{x#a-lx>f@K@LIt8cp{+Jun>R! zt6y7M8yq|z_YKTu^FH)=KW)T4~_nT;?c>@5hxzF|Pc> z+X0=1fEfV9b!Z46Do*=kvAfIP#q?L6BM+GPE6+$=n9uk`K*)@wT^luxXU+G-B@8aq z#1JdQ6+7Jbb4A?4?9COU$yC986_5M<+wrN|r%s+O|7dDr16ypSnB_h_3Ng+Vysh|6 z`I~|_g>Sy4)3>dEmSOpBy8$+l&<~YA`y3hoehfAiK(2`|?lid-lYx%J626UURua=Fv!o`Z85Dh~ zU$YoV^4KQJunM@gu%AvX4;3m9e|-@)#Z(?7@VT1An1rkheA;i)4=__5Uqwo-F1jQ5 zF8h-s2ksrKHI~mVgWIsehgR^{6GVpPwU{*%vm*czj$d!D}@pc)E=1aH*E1{r2oYHX%CaTrz_%dR}9WLbEI}eWJj|>b@xs#dF*%WU>$+-Y- z|8I5+fQp~+y!M>OKtdzLl?p~LLs5%v$~Okr%C~e&QNKmgo1(wx66vQ@to_lT_03ua z6nIBr)t4~Sd^%=)&icuteg$m%pp9L5i8gjq&TffydkG=!12SmbyZeczfpF8K={CtyNvy(5{L1)SwLA-b3o(N|$ zeT_AD-Q1}f)k0#i6>Kfbu& zUYnkd=Svi2={Qah#gtW(Sqq1OQk_v>~G*Z3H`6ZE1i&lA=Zsa+#%^lp)ekK7p06)yF)x#=7j%`ZSHV z0|=w-3aAy8PWnDbh9roog|8vFk!;F6kc;a3@m68v&U^g&`R(ISp1g&X^#fHwE#)@sjhY z9{2g>a`U%FFIGQu?p*oQ(n8y69THsfkEEJXr-J8YTl==vZ(IN7TY9(ce={g(40IX< zT~`l)qvJ^Jl7t=lNoc@%fi%&6pld=4lYOO!=1Z8cfKhM(wW3mirynykQ&OdjBwauK zr2_f!UF5vfZT@Qk?u7yjdg=cjeFtln=t@Hu|M(t_p^?M`%nLI_EJybTy5mQrDhSY59B)nnoyF#c!c#aS++zV zkzZ5+hc02Xi9_Kwv1A66t;nImX;=#oHmFZXO>*m{Sk?NFCOEdXq)A`Y;5CgkYk#5q zBfc*nQz^Oq<+b#~`Rs6SzAyrSV!6@a4uBZ};n{$2cYs_;T=5Ec%>iJe9L4=FU|=6+acaDR)!$osa!lz8MRwmlur-)@io`Y|`Kavgu@j zJUSVN26z0|bTT?}i{w9`sf_%3=uh+n*b+Xt()_pM=-j;>n3|e$ef|A{LiY0TJ0HCd ztE+$L&X3+-Klvk9njFJ+8D?lMJh4!tQBGjHT5>CCN=09rc$>}t$ZV_QR?;7JCproJ zm&1UWEY1QH-KB=BonBdn%r+^jrpQABfa#$eZzjt$9ykga36;_HIx8%GEt6q|QqT0r z$XsQ3_-r$iso)#{=z!OoBU4(ERy-<`QTnEZ0zPb>!4UmP*fQy3at+Fb;ece91;ZLN zZ1uA~R>*h<6p4X6PTm`pGA8dR^%I8=-}8a{PGAE>w*NUqJ}PJ{|7*D=;2TTY>TEU1 zxZ?xeMxGE9nMpXr#5U4j7^2n5q&rDK`-L6_eMJoX5^VoRQKKFgap-R-n~wVW`lGqR zp!-H8a=&wNw)xpN&sTqh?SBZp2r>k!itT@fX#`MFn-M_eZHheH_BSPOKJ!f3hYCMj z>D$V|CKSrDU7_fj2%8VE-R0UzL0Wlwbp$W(wbASf@_(cBzpOFe8SAX?qILB$@Vx}V zz&qZ7&3?EyCnm_7;_#Z*69_!u#z$S_^hwuTgFT$b8?{row}y;_Q9a68$k5Gj%OO=t z>^A!2Sw}3Q>-mA)AOoB1I;ac44}pyzrGfTSQRqnn(YW5wL+ z&OWy=H#48hzY^~|G?qJh!lnEA`K|ygdGu5xtumnkeNQ4Gio`t~5LOC$80IkzB@($| z1Zn(Znx$Kv$d!C)&&o?fJ{?|X8(O8drR4y_dIHBimr65k_V?u7yY?T*KCyrQFir#T z@dqk=I}q5p13=tx^=}t(&WqKD7ovBc6C9I9a7GjJg`P$~%Qt^J>2G~7YWe;OpO6RH zc{qqeJKu32NaV3^G67coQ7=CASI1K`uSI$HhjYt~Pn;X8JUxD?G^>yLiSh?1K1=P& zV7E?XAFlju)!*rJ)z94l+wu<$0bBLcpr9dO27s;lDa)M`1&L!9g1gHR#lkPrE#)H( zw$mbk@wAh;gcXi7Y^R?JXIPh%Q9wz)D*XXvWs>%i^4eEMwH~eVw*AeH{@MM`-SV>l zk38}SQ55~N_rIUY%}vGe19|7(hws^*sJwX!w*pS_uo_+zfN7Y!0pG9~uao83nqECtj}8DJKJ+lM@rHT(-JD z^G~0eeq(a>wfOM8m$Gkrhf5C*W6HrB)HlD=Tm; z;Onz=#92a0B|knTfMLm`Erph(){hi!MG?}K9f^Ps1>hXUzDCu(EgcX1`0&tCWbeZz zj|!sXW=27$F%TLA*4E_>Th1Nr`(X=R5jNk`W;f7Z(9eDeABAKJ!WL9tRSkdflnkEt z$9uGf+&td;_brIT?_HXy|C^I%$}dk`gu)l4Z(INLZRO9^Je4_(0NdK9-)R6a9_Dv5 z1ZV)55kRBECX8;AgBb(>(-AYUD_uep_U_inzl=R;%LuJ)N?uzq$hR`|>CA7NcLI2Y z+WQ3t(*C|aK3hu!C72s>?g>nuKkd$+8>pOm-IeDi@oIM%yWbd01WKOQED`vA*GFT(sFoCK4A!YAddJnIW!EG%_14|WW0KNr&JXth*wFJ8LT z{NCh5Ev{B6tCUUpCcnu70%;buJTvmGoXNHI=!TvSKs(~3lDU}~R;r^ZRagGz%(?OE z;ltDM$N_v<0Jj6mC7yi298NDWzpMj>PZ_%Wcoh3KShY^12>E>Px6TS!x|Pwm+~DC- zO)txARl^hys%?NF5GN-|y6-H(d^!NYWKk8j1e$9L?pVeRJcUy#2L^`u`e4?T&ZW{c z0PGw z_0Kf!9)w%}p~5$%-)&N$42P2gqT*UZvy|QACw)r-zHb_*%z~G;RQ`PfSE0YOD|3cT zFy>32z$U(L3dotDa|phnyW8U@Gaq~GG57S-Pbc{KQXKPJ!H>AbrHAUTzvk*^PE)Vw ztpKlI6!`X|zx12Df${LBMh|wK*T6@w&dyd&PEJ6Un{}`r<`y!Q zUQD3xZcI%??Wg3BD3jK@=_pE_?!7j8T8%^2KL-!Tt>lF>CHG+5|_(mR!U`-Tfa13 zy3|`diPO$M>N#-uKg-O|xkeS|ocR3!Y-vbiw9D1;WHk*Q@pJ=^dH83|gz~VWe0?E< zQz#$vc`_;uci7de49>UZDXNJ`qi(mh1P(u*AW6DCo`Bl`IQ^G$Ls8S+=bAn5%%+Zh zPq$^O8x8FD!XEV(jR8*bc2JOcb}PVeMqgV;z=!DvLt*sJbVB&sg#ILxFpP4I=L>SL zCU_!78E|wTA`R>oUBJ_#f45qVKR-QR{rdR})q15wejp!^?i5~rebROUsH~~D84p+U zrqsF04|fI(-tP0WoYiF$1KY9*AXNGyyT~&i!P|=G4Bbi-_8u+}nk|?AuJlJM!3@;V zW>UgBr;I{=_bDO&`?TB7n{mH-z`0v~7GQOi_N}^8W9N=I_tE$xm|=g~HR8t_XV19u z={H<$eZ{4UeNdwmL&{jqMd%9KJPELziTe4-u9||=0VNko}b=Kh1vByhTJmH;|#|2_A-$*l^etdZ7 z_zyRZEd2fSz*xKlxDDL^#j?$jkxB zVzgOzMSQrtx6l`@A^tARzPS0 zFwNrOlAmd;hjp9JiGpnyubDL_B+rnA@JLd)Kyh*&qEoL%)1M=TSf6h5p zm&|E030W&`ZE__cxx~3JkUXt!{gf#siR=Xu4E*GiPr6Th;u8s-@45GW9uNGf=BYRK zS6_O;H6}0BqkKLS@fCp}PEt?6aQT=p&VBdRk_y%gVxdO#X z`-W2|f-J-zAr_@X;~*l!5ERK%O0rCwdPE-KT9qK~;e8?jP$+P0H*5=8(hm`0ZIkh! z1cO?_(gju_1f#Ii`tTmd6HxE(?#Uc_N3riMZ>+D82%M0q{J8_b`vaV)87I+*b6%{1 z49<&TI<{wh2*Z+j=l*!Sd%Ess`U_E%k;uj5u?X8eQ30R&tLF0V4ZQB}n+t1=&yQVd zJa=)T<{CBfgDGa*8H*{*jMFy-PQP>2Z;GCIrtoPbu&k8}>oVb|Z-O5xe)3g#Au7)J z&EmIv`XB)q354}-W@-2B0<2h z0|(v%RQ=~}bnIyDhp)Km=sDbHhAkaD3P51h2?*T6`G2eFk8w%2>GQ<^eACey4g`#) zs*N+N>y&X`JP}w2%TR|<#+hcm!7$Ftj02N@GXTs7i0YZGG63QxR>aGt5*y@dH+nwh z&cD5H@H>ZwM~-9;9ywBw9Lf66eI-ItjLBs6@JIxnOg}1nzK__`HQd?v$?o0-xtj^V)sJ1=AOkzy}vv$Q@JoRMMZ6b zXoAW(({06WTmH74->LK&r?NLVhQsoq;2STIpF+Vmp*Mc&^Z|ZbI?9PG`L|R4RXl|S zh&1$}wJJbrYnJgSC9iUJ_d*SJXAvJoR>=Rp$Zg|&<)5AYm(JbVvjF$qcc1&(*S^M! zeC)m-$Aef&JsGdAzPpCo0JYbC;9@+c6&3q{>IBPxG&UD>`V0w&RARaT8VqW=HeH}p zWpOErpRM2p(JWLrvSO^jAUKZ`=x^c?2|i$lWRq{oyD5Cm1DqFZJ}|%27+_h}VPi%x z3E%W10#jBijie`l&}GO$)pdD9YIf8 z{c20IWWvcmAvMw9h%kmNT`Ej|w46n)jIY8xpN$%%KP;nd5J1v=`%G65pHIfaRjPsp zxYcoAf1i8T!2`V~dVBEsQZ@5p5O*j7inR8|ch(O|% z-?dF%{bwtDDtunt@;BeY21B0)0gV9~5@t-W4Vw_m@UY2(vdGIYiC_{A)0lqSI?^WO zq1HfzX_Bb%jA5W10jNQRo6MzUSe#+GkOW_{P9#3N$^5 z?FEQ|-}sH+Xqy8c#%3!f%*UHE)4hBwpnBmfX3lhsTLH2mm(aEieVz_JErB6z;Jl|1 zQo-nA#1vA=PeM-x2}^3&ig>^T{#xm;1|#Z%71E1Gis~>0PA)CE*XHJ8ypNuZ@M6GZ zJXG@6BL6lISY3YHs;ra9bp}|OjM10F`v6L8h)S*DKK*;Mr{DG1g@+FAU(E0;LKv8< zV!kTiu8uibT64AZ`il$KwJIrkedv_V+$;X5Ou0q@1*IT0nLLIC0x($JKrYtG@!uh0hFzy8)Z+1X%aXM^$&E+qLu; z;?7rm^b(2JU|S?)YTwcTS!vy)iotg&k8-o02Z04pZW`%J25T zf9Gre!j}QqK|q$LF~It+XZ7DH{2bPuKSw2TpCh^a39cl~lYo;_i^n9_ z=iHUv6Hh$hKK8MXMK8YiVlw{s;In|31fOi2IXPH);dxgdyU>X6LV$?x1cp4S1M0SU z{zto>UN=X7C_`2hr{MEZz*;u%X7QDvvvpTn)9;6KAwflM%AGzJ05;EFzyt zjPoJ++g-SD?id~@{{T4t(b}mWx$?^|xcbt9OYseL89Wk*lk|!1u=yF~ga+H73$}t6 zxCg+cF}984EXFWbF1c5*$T)|OAYdpa^TY?koEO5&3;|2yTw(K(%@Le0SXZ}8ln?T5 z%CX|aZES2XP8#IgGv8eK^b0TjaBXPc`RMow7Yz-&m~Ri_>KR{Cf%9cUv1toSz6bJc zSQ(C}GpzF1f@fWJ8NAegwRU}5-92rWPY+U>Y0{+d%vT0q4QRMS_?W;Wx%AOT`v*>- zbdj%Agr5ah^LBt40-K!+VCN_R)@kW1;&-aM8XY9x19=>D(p-~`CWLLlx1-U+uz&{% z(W_w*ND3uQ0e$Q*9ssNMtMV|7j(-1r_dkTt``p;*!3Mq)T$`D6 zG2WSn&jgAQhBCK5{V{|F44Ev(#Mg_?Y~Y;$7caUu=jTkO!*c*M0!+z=z8MPi!+F8x z0;`LNO>o8tmCemKtIQe@AC<=VN(#BU^vuUTF^8qjO09@DsOF&maLN&i6EdVsAF@7^ z58$Lu#)C`RR8ajT4}vH08{=(N zjbdfZJvuyCeCjQ4If73J@O=SX?aM7>`nWm`fzDe3?1^0nN|^o~={Qhx37#cko9Ryq z3c*D{NKRU7QIYF42<92Q3i{8MHkzNjaIyB;bLYw@7v@S>fg~$_NE%J{PG#S@{m*y( zF8YgMyLbzLux1EwcYt-70dOTFz?8lTJBryD#Ap1Db;2_kosupXrpYYxe7^aFYK3oH z{#gfI(l!#TUQ0`SgYz(2P~jzfm;e0nAOErYi@*2__tXI)!Ua+}ACshaAMCTDH@P8kju8vm>R-qz7jO3N`jWB z5oHLbkuh4BXw^-)qznOkUy?MbsPz+oNPXpcBkJpk+*=0v+)t!(gWox@@92xuQ=G(S z@mx43ah_sfoWvtxNjwscL?e-SK+uTA)@8Wx>B6w4+yTEWI<(W(kgvFJ(MXUGAl_)h z^iF4al8!P$ck?}PQm*ybpNnvNCy&Se2J(ey8SpRRHNW3nSZscAdaitCY6>)Ke@hqY zr~%AY{`5)Xa3ycs{!F)f`<*aWo_t~gZ@ghbO`Zt_8_g!H%rKq#8oR@Pjm8NbgYjCP zBmpbk=ubYgxrJ~^8Dh~_nxsiZtset1pE(S-Q9u&f(|r;l+dw7ZF8z7wrI*@9egeuL zli`2S92?yy2Edyq`91)b?#bhQ`q=s>=0H%}1h`%4&oQJi9t!qirpKMjG@BReqANHL z@MU6riq4dKH|5WH!;ApV6E;`aJVAB~Sq{;b+e!n#8p7udtDse#W5O*Q*ZA^}UVq`x ziQ~^4J$m1NmEBkytX_E2HA)+ebiP1^*LEMx28*of)0}H>K{!Q4uEyXnXJQ>zbjVO-9zd0 z&<745dSG;QZFzQMZ4OPPdQ#~;p7*pJ01{0O4Z^o41Gpo@i_MULce+z*1f#TsZJ|Hu zro;utaU%yz(2EY_a@i>A?RPV|qWjy$RriI7`R2E0=PHw{t0rtszUdD{k{ABd#}Fv6 zcG*sVt>S3_Q1Mggn=wFG%V)aPL7zfwLQgreYcruHztEYlu{-}a5pj@mN912nOssP{ z&>wn|V9H5gn1bFiji5p(4O;eX1U zp9!p;dIN9bhKS&CTp&!QUm^~8y{&lx1D5gNTfr`c$k^J3dwqGWxx{ZLdilp9(!w@3 zbow@Lm?2>E1%2W)ybu+~G;ue3JAjoWmH9B^P2LB8--#2v|6To^-~9Nir}iECyZE7p zr_x7{>i5Eg6`a5#E^^jxSBNraXY>+jmHH4z zxmL#+HuHcPlE)vimsXtA#kM)?5R4#nvZsMGyyYpXRx5Fg$5-yft-hZ;bm;Iq4 z8ZZQ2!}k9l%q-VGes;9-XQLNOFa)T)X$(*RD-cY6^3PWErtG_I|J#;7eLMMYaCRPm z<;^fKgTmTkduHKNW=z1zew{*&q`S(IdKmD|$-m42WFz_4ADbMMv$cQhqfQup?jo5a zs8Dwm)q=sk>s{}{IdQ&MP2C4^`}8Ot2SmbCjW&v_)kn`a@iai3$`|lLeH#fFG7cS|oL_Eydu*(-ys|`jr))Pc$58&cK;XqW!7fXqZ*znh z0cJFG&JXOabQ!+5t=bI;E44b`KoEZmRP|9bj;P|sM6m_l?2?rQXtSieTaI-qj1>17EbCj8P*_H5 zZm)@HNj*Uwz8W0v-~o@=4Zx&(peLJq^1$#tFHH5#tZu9|H|lk+2u=BuXxtev0+LuZ z(X(3=3i?Jw1d|~#{Z4Q|w^4w@x%KoX1~F}rjihDDAnr}MUcBlzhponGVEZM!=Hlta zncCB17b`Q1^Q03m3Ke~$7X^{ZnnnP_RN$t>%^;x9e7gk@!m%Dx_Eu-umI-ml1I7y> z{lhS-ysO-=W$6Dc4sIobyv~P{on^baBCYI2?9PB$M3|7 z=!0%$?H|-%dD)d;!BYThOE{4`z=b1ibwQBstn8lo|9a@pUej~|Z|G7Ij|47ditbc( zsdi>zo^yoFH{5ZwIfruuFXo4rrCXWJ76~YJx!WoOAgoy_gwegZAd@HC=y~SV@6Y|? zr~dJCj}-df-gEfg2k|zcRJF2!RWo+N@vT)>&{ElmDoaq`g4PLt5KL!p%|O1-)%hHV zl_{QZ9nR1BB6KJ$a0Jo1RXE#=w9+^v>x1-COZz$`hn&gji0=!4UoEe@;d(RriJr{y ze{^8q{L^D=Q>cV1z8-8P=V2s}h~W+Z2}fL+^+yAM6F#fA#tpYfx+9#>(gr1%m0@AH zI^tVEe>})Ru>-l%V1fb|CJ)75$47oHfE>>*EV?gUnyh_$W(MDbDw#sA^I#5$(fPe! z+W{agsq9VRTR6N0K;wXLEW;}lW`@ncFvV|zO!Rb9{7A+C?rw+i?-Kdf`N!l`sABv~ zBDFGFAtbi(|J_DPd=1d8;LO-V4?Ms*&;9Rz`Bzzf6bQk`;?pNx{pIhw#{68(6?(G~ zJ__XB?wtRxgZ@><1}qN526+YpA2W9s$3&k&_1wA)RtaS>fa2e$QGa(YBW8uK7DY{l!@5uyJw+bQ ztDwW>a=F=CUUNSd)q0*R=0{M9PX}*;nF5=BDYY|Czo)f&c zhNXDkV)|p&5WZmL5zcII>jeae3Q+#5#XzWHY6oB7I_GiOdIZhpLHulZl^ zY%4svea8fpKkv?k$xt+hlm58mPbE&}PQ^}RPM7j^Y2RP&uU+!j<$hfa(A5Ig<6H5y z%&dlh&(tU)-J$<~s;ls$M*$|fj05npW=kP};{RCiKhVh(^JPd?RRUm}1{i3byWrAC8xh3lPA6}U(_(xUGU#8H}0@OT<-ojDFSEn;xadO5`#Gir_nTna1G|V;#PV3WRBW~Lc zK;e&JTy*x=2DJ?mln^4us?efdnw5Q?VEcGuZ|K zwFo%lIX;5Z`S8R^-!*bP`n_7J)7m5Fam}k;&-F#Pr3g zhR+G7lTO1LN7nzbPG*SApNKp@E!?;}yMSL&zoFtw<#yE zUJT{Wg&*>+_?BwN=lIJEko!i1O=3ZSkB;==)qr&aL&fd;z>FQscQbKD6)I|#|ns5|8k;|aK*NU-+1E=X*VU{*;JU{VrDz&aPoqD#l zx#gNf`@BY+GmLjX&~6N{I%<3lwqO$-%Wx&%Wk@9gs|BlkOKDBg^*L9_qSnl)*+^i^ z>F8^nYzts$O;q!$-zF3xyn7{ju_ zo4KNSYGk;4ci&KMU3YgLdyh$TUdnU~ixJ>_H3Z0ns?6y#U2pX@PjC5Ip7}b?#I573 zW9&07`Gw=li>}tUsdK+Vf!W0WI)Ckmxk>2ev@}*nvTE%7`CpZBLPxj+fDQ^p{=6Zc zd>@VjgfhCp?AXy%eBn7$#H#>!7cj)f0jLZdEtFQaC{vHS@poOo^8i_z?8AQKH_M6e zom^4nOd%GF74b=4$_SN1%=0fze=k`=5-ITz+}|Bb13C2$jkzsv<9MBX8J~c{Q9IIBzdT1+w5|?4(b}-PA&=s=Li;Ny zL?1_~PIE&?OC?MP9@Z#x2;u$a64L~eC=nD;?JtRfKycaiSbWkr=|>P?@hap)fEFGd zXu^)GTbj<<)R!9GUCi&x;y5fAfN2;yX&~V<0S>snB0zCN){c}MH9rpOUhi;Zm*m;V$efJMr{^N~JW-#4kR`m~=dv@&$pC25`?-(7+LE4a+ zN~l;202Edxqe52&PNlAjU7ro80iXr};T1;9Df6mv;Vb?_QT{+V=V~Yr@j+#>D1=O* zndARTGvpRRTEjG|GRP2-L9X@Ec26d0(G%4t0iJ&PY4hO^e>fVyZ)S=sA^2`E6WI%j zuf1%>UwIKH<`3h`Ky~=q9KJInubY#6cBI{JRQ~uHe;f*g!L3ik@l+#Wwqz#En*Ome zo@bo+Z2N5-VFWDaP!rH`aSaoRavoVsMZjiBzWnG? z9P#mT_5#2ZF}1(oMnG^0PGXmIlwbw8@W)#0{BwA;4yoGJZQDdx;sp{O{e&+mmB)t6 z0vs%J@uIGdD^AAofp+OXiGk)9g}4e(`zSy+38)dkang(J*9*bp+mXgXZ<3l+7TS}b z>>}M^jz6WVh+P)71DQrj10KnQ_+;fKynl1sz*y;jY}=j3`+nm)Mn-tt9~HDHeAMiJ z?T1QTALerd0GIr0AN*@v9|sUl%dor}12hbHsbRrMugt4P06Xqqh(>XS=UjyXc7kxu zkVK@K?`EF=t@0OnVcUpbks(&jV1l#R-u(BQKg+`B&wJx4V~*`!0Q1Z<&zQFM_DBc4 zv}sc-4gtIo1AA@pwRMTi6Azp5%^QkEoZdl0Ks2W#jEp(LR%YOr^YX3(dsq8!niib!@LO=Ze~D|7*ox|nuwE{MJ#M(M=3{<@wAxOrMVk8qG$vg;1 z6hBrQGiuYKdnXz+rs$ z@7Y3NZrRgc{QjoR*_U?hfTAu_QTvR=yLYBhiR&&vDt1-$lNkeko*DrxOFW8SjQ}z$ zFYuc^K9hA`+f7x zH>FcoUU{Y2-Pad&@O@{TaVZ4dr_G+;75V3%H4`sCZ;IoiSSQ8q0QY4e0w0wBK~aLt z=J96(>DbZ)9!nMx+QWkZ%CX|s%!Dd*Dsf(F0I1^kWt76wFz}T>WrxZS%9C0*S(@Bo z)&d?)e9}rFjKeLvcCoRd;Qsu+yWd(rIP^fiwe#)dl9LTie=y|zzHtpS=A} zZpYrDARQN2b469bWoQSEg0QMNx6= z{G5Al3d~ym7a_#?EOVN}>B2Iy@)(uh3NinD)$5Um52SKqa|p$ z1beV=?Mqw#=CZ5Ty#MUeKiW7xdV0{k6(=U+Gf8Q--CvZDrFCgFkavSCBH z7@U%*Ph6Xhy?<|8Yy77J10)ANkb#dz;FUFuq$(y7LX`$F=^$%U)JK*ymj3bR-1xCO zA`PQ4v7M=muXcF9@h4-!frcFakP{lmPnm{v%1q$J|Ch0r_(0Fz(u3W*i|hC8EnrnZ znTQOO$Icu2s{H9wf$QD7ZwUBd%~yr5<*4{MZdwP!96Q!QpWRTOVgEu@oOV^?bN+!T zFnjsGrp=W>RjI@jCx=wt)RZ}qqI?73d*Az>M~2WWH0G0#j-SGT0QD2kt};1%7yz53 zLc9Vf);x@QVQv}$B4|l5{0kBxUqwC$F+oRL0e!@hD*F>F2d~E=HC-`%lK>_(ENDZ~)f7s#XNJDxi-6IA*+D>mnaX$DMQI z=Z&M%*&C0^#$RZy{ElvO$3MTm(S+5ORJt+f#<5!uj2FYd+_5MB{f(O@*7xoi2cuDm zlaa_kSrAZ_y58aYFa7Ite)@df&yRE2Utx76K#c)1s4_1ZbTTF-ALvCI_!pvc?hq)T zG!syaCE_}d5Ss=3PX_g!l|4@0*tW6{aN2Ggn`OVv7ySs+{}}BB;G?tgSj4vka23kYnbT)XB#R@D z%(=s-fbapQfJ_5Uky*z7?2^n`*G5L!%IKHbOt7g0KjGYqFTQBL^{sE2cmu!9WnFi6 z{AAqid>RQC7hhdx#-Dt|BHP^dFVJ zDt6w{>)pL>`tvvX)!zO4D*&~t0KNg>FVm?Jpv|X0=Z=yB%5R)3)daOXsQL8iBrbk5 z!(18>_+|WjSB@wYkHZB|>UG#HE{8|*2=C$5u#{q!G~AXZ{E6n)uU~K8cN#kpI>2#ynGL{P; z*|t5usjrs`opjN+02tSs2)Ri?T>Z&zGE~0MuQdda^xkeN_5;+`Dzri({c6?LHo?TQwy?#BU;fJkuqn1G-c?j;)cPER%dk%iDp1-!S8vo_+dkZ?0%?q+ z6c#dLVRNAnJ3macf2OJa;!%8i_{C!3Rg~O`*FpFVtp>oUA|Wkwpc!UGdLbxz^k=mr z?ckheBlu-Mkml#|c8H_SG(KUGUsphAEI(kxAjOmZU{x2=_2!*;y?J(cqI}1W?$YBs zb`-)QmXj>=2$O-X8Yd$$tatv5>k0tVbQ2(bjWeHcddIK0$eavwe3Y4$8R_dd`96}x z*?wqj&Oagw$ovpWT5?wNE#{I^c?S7kW&wLA)0`8Ujk5FGc3LuQ@C5tawQE=K)aunb z3TDIE=Y1GUo1ZtsBc~VEJZ%AXRVP7#c3E-P@nXLCKUEyyNx14&*C*U*@Q+p}diDEQ?F!jjtP!9L+k0 z59p@a0MP!^mkVFZDGz1kFa$1fhrfOIFJ67{6Q6qM!mcGt>V^iFmA7m(g^5flR)@3o zD)fswK$eE1mH=g4Sb~<-C6Ca|M~$ph90If_Fu&l*G$TYcjEjrMf)*k|qPWB^k)pE5 zFCl4{E40-JfMGhO&l-o5uKc!e%)sRE$hGSH7Bh@2O~Nx2-V0c0Br?S3 zi7{ODsZ`j2_iBf*TKGDitvoa^Sp4OlzWiHzaME8z8EcqyRK}tbXP8P|6+2e~e1)%Z zH4e0l`ou@vymVa1h(0sw_-J=(eSpuoqojcFGjT*bN!cI?_~D$9hz%2F#`vG@h#KP> z#rqqT87^s-dC&jKzlKOU273Xzw{MRvUcOxAl<5n@rC8ql9Ck{7r10VzlX>!ClkMJ) z2cOA+D*=?_KDk7`s@zxd9VfZ~lano`aYGpxG~$%fB1GXU;}hn|k7)n?fsA4y3Kbb+8i*_D$g*LpWNkG9LMZAE@3JsV6C8w)0)oRz5HKeN zMpRDfLtTQ$X(dLS#Y$MBu&olTUU@s0**?}pq#}yguvk2n=LeK=H@g&P27KVOQ(DhG z<LpJ{XM z=qNz?9yk2YnJw~y(_Q3-of9(S-TXf~a?GC6GA`o(RxHbB7L2sv7BRD_~Q?mi4Cun%V6rDo<{C_Ho=k>_%>=3<$3^_I z3YN7%T9?)#n2(|S7ojDCOREN(mech?0pBKBJ1|mwde80x4#?9R2i*%mg|3Ex-e}PG zoJ%?h1Pc%W zq1Ep6qgs&cVlw|wzf2PGZHVQ7OfU=u{js(X2jgyn0lO=`YeZV zaZ}03B*urZF#2IIIutCx9r0!H*eQGGwV1!&+Y|O0^A0dz(OU+eN<|eL2|;W+@C@sP zpoCQkF+QVi+qP}4=f=EgOmAy8_gtbBo|$Z)f2zrh$Fc7NbjB?`9ve8LE^05Si^4b| z6z}|l5{&^&fFKd;#e&Go6D4!^KwtLWt=qGMBSWMO>A{Q7*2o|^l%-GRQ6|zmc~$Ou zmroeq7*GR&<j<+w)({Q{lSlZWG=esqNp=tVfaBTZT_k$l&&a0zsBUBdD4^z_LYLhrno47Kq~)J zHd^OcN1`=sgfvN>t@2;QFusEaSzm`6*akfI-IXt!$1}sFmqtda;cKr0>F2Z0~#UOzy4o;v$Z#s-c;yZkPn($ zv0jX+z*S$s=#+>WD&6DFHdg~|s`UVgfSnieD$M&7in~}_pR7<-_!1Bjg5Y+G3 ztB0i&p$jP}5t0Ze{guN;d{?s#ON7Z}eQZ}DZtfq*m>+K4HStfIH)o*y$rxf0^Ho1| znkyze@1M-$D|}V(RQkMh*}pbSI4yS|1{6aBaH{;-N4@;f_QL>~bH|thLf_+#|JiCQ zH!AaEcHaGe>38>j-I$};3qVd@`@#$6hkyB(($_6v*bYPB2Jq=MzOyE$U zFrALY_&P6?rFh7IBQ;;`AE8X$-1}Sng7Y>p7RON;TnP})!+Ce1(| zt%dh0O&Xg-ChA(unxPH$KA(J9gC%7S;oU!F6kn68cIWNAS_SkO z_m>288Gua3JY_yIC-Exdsn0s~VjuNFaL!E=1!UIn$9EhE4hPaJT#l3oZZ`0LMGlC- z;r#(yD@{L+e{y&o7i=5#~Gy9*{BeZXX1SZ#``W&EPCB={_q|4t#KK#4fsdE6UMnb!&v<@LiO+zmyUQpE1* z0v3IJrBAsvwk9zEf0VA|`1E4cX3R@JuO<-{-tN;P8 z;!~gXGR*RNIau|gwh)$=!fCmhbb*fw1=t{fFG+z5x*F=trOOsIf9d>lS0-B9m!nvH zrdUeGVK4&~mj-ITF64h;fMe;^9Ptd(rrSyH@crm;$&w|3X=sso_IJ1aecxLzu6}H& zd*|!L@vKQ;tt=kLTLYvT_x@u#;GQ7lUZN(XC-AVaH%Obu$BWs&?&}}?o9^zub;E-L zpfHs;86yW!U%4}#7hm|-m;8CuAH(!{>G6M>Pgs99pc(_dA)v;E8USQG8UXC4UI<2E z=|2(h06#QWHDHHU{ys#xqIR(0>xsn zv}ENM)Y0&y9_Z z;fs+p_NDEmYd7wE=*^uye>IfJuE`Y2W7!f^e~>hZy2g02u_YF!>SJSA_t>4ympA0f z*$0Qm2Y>kP_FaGf_U5fU+3{}Rp~6<>KMsQGojnyl6*=?uQYG&j0h)Fo#jln(8O~?A zLs9-HGUuj=0>Vr3<5gIR&wl=onr-Dx6g?gT|LXUD-wfvYSkAh^QsI2ut^6uJqJE8e zd95ivwaS!s?Zikp_c3;)SP`pS?ha`>}R{)>_l`H$zBSpJX0(Ak&7 z;Uy#E#V2;{%9%o*N}o3mGyo`DRJl{;Q1Pqm@qNOu952csl|!UU?S&*qScVS4O~)eu zzZq<>P7;R25ZFFANMcZVrSD$%V)vyhmOODu`}}3CiYl>&>Muq@q z3X$Q5zPc!`wYUsXyu;C_UgU=f0Yl<^y;U|OH^VK8tq2PNG3PK;-8R$w_; z*3_21t}*?A-Ak8D{B-kM9PpjEih$+YvyAIxAQqhvwU(gY!pT~KqEqgIp`jtufMjrN= z$Kv>$Czg5TTwsywK205cm^2v~BT_jy@$lorM&sqPuq(^m35{Pg!FG5fO zq+Dm863DE>V}LAnKfi&`1HUvdREC_V%oe$gqIg3rQt*^PzG3iQvZ+?)R~m2xq3JXR zl+^Uu3Er{NFYOr|qyXm9c5KJ<&u#rL%THbP;}2eNadZ3pQ(|>Hpgy1sl1b2w_JVaF zH0aGoN!2cjyXQ!LF2}5@9AKCaB-XDQR!NfL&_tC8Q(R1O$qYmq<5Ix=R7H@c`C1^ENmIz>!uoJ1cppwnxT!IDS*EEedGFZRvnalm7NjGZ8UUjU+L`HdBfuLSX;7m(s-#D?irq_ z+pu@IbpM{-?j7aQKEQDGquu!+p%_Dm+PMRt%tPf)h3^{!z5&26l|L_r3D1l0%7FAK zz#>LP*rzS~q8EaZ+)-LHZO%;}1;}2)KYo?bU>qm>FKwsX;0ob!=05nr51MN~@)1Mj zuT5{mjqoYPdWfADu2ovRrD&mR7OoEpAK|` zLb~gvLvUFBbQ%C`7#mB+;nap>i$tN+Qdbur!P${WFT8g9PkOelSoV5*GWDUx`3vVK zaue|~Hk-)j1!HokG;xUIy|f}_f+Dsd3!~{aMhJzoVJ|^~(T_fpa%!42Ia|SjxbhL2 zC=j7IqyX`AvZM7y%=~gOAI!r8fb;89^+SsmUATG6wp|-b1uliBno_CsNIqItB6_`J zB^lTNr7QF3)Clm&WOJtJmv6!j6-(u1sZ>0R6Oj4})Uk5eU z!j^14*E*J+z+(@555PY5V4pJhVLy0Qfc8=QO-52Cn#=&uyM9&vWH2=v=(92O$z+O? zbup~8q|Y?^>in>#&H2+zf#aY5Ih~JBw|4DXbL%a)B>wAP{Dm+yd$AX<06?kyh8Y@u zUvBl2X6*3?O?J-?yy%-WG2F!MZ|3;@w_#!MC>en$taK6xiOi<)r~HoN#jgY;!$cx& zHWy;y^MfP#k<2LNQW38);TA_81E>L@HzF#(D4Wy(Py=By*+f~S@<`>7`a+jO{h4k9 zK-;B_r7s;B$>k_;d4r2JB9r^c3(v1!c=c7MowoecUrFY3vHX^|u>Om+@`fg^9{~i? zShTTK$<`pW5?bbq&Kp;gJa>YYbvoUy2mwZPuOM?}b#93tmD2iHE6P|r1fjFYF#1Sv zVVhwaC|W~c#iFffFl5k(#rgt@0v1gTLOk-wg{5+;T#B94)NC$kp4YUYu5rP}H(qT5 z(lIE1yh($vPX$4t$WKvN<;B$#hDjJMllYTEdV(}i7a7n1=8Du`K6@_J{qY;5m>1K&Ij& z04jdM_{>G7QpO?4jkAW`c%M<#U0E0^}Y$AskO~U@WgW-;I=T*KFng zh&7{r&H4b?(yU&+Iym>d^CIOx5{4gwLis9&2^=2y-*^^8xR zf8n{v>cka?QcQzMxH)jLw*+X^@gg005v3|lwoWeur^T`B!qW6{m2=SPTe7*_u56A< znG>3K`&{a0yV*XbP2|euVZ1Fdj6&SJryKeFo&DV1KiQ=l0Bbk>sX?HYx6gQ!G1_Fz z#y-rsSwsO2$Z^g8obj{5{nt~zvBQ|d*$Y5ry=l{?;Hs;xiuht*7_MwI<{RkJr}Ar_ zHe+}G)J&{qeX;F=)#yyp&?g^RZ{JpmyOTZTtE-y zW)97W;q9h$G8IhVQ>JStisgrQ?aJ>S9Eg-UWVkASl|_1k;`_{_j8Zujl}8#40wsm- zBl*Z2mBdUqJF>Pj6u7+bjV0`n3jzvdPKn~`7hZU~dvE{qSsbts$LoTzy82j{&+!Hk z+11V_xtS!zUA~eD(fvyi24y6JR;X9T1+AxeZOq!A2rImUm1s?x%kn&}&nvHGv;nx^ z2Qjc&a5PMg_M7t(<)zxJN)n{5<0A^3l`5%mD=q4GcT%rlj@&DJpNY&GU<5Hep3H*HF0 z@4eGxVFZNvY{-*Q~iA@uVV3eII}*E9o;a{=Ob!OK^uK8v1QK z@qcn?tn|{}eNf^d6}jAKpqpv{FwIx``lzy2`4gT7z+|!s$&s6sf>G{40#p<;<=AM_ zjlNtsEWh;j-o5O!y#Dt0k38_svZjVRzIg80ZHv;WOOn~FDevpWLl?Xy5X7D8wzeN4 zN(66K0F!gFR?m8EHa4{3w*cm4-5C z?WjB=6Ie7t>&=&74-F3mDXa{f-P*bME2k{GJd3YQJhkDC7g2hA90x1m8B;x~{68_L=#( zbmAlvsjm#hvXe2Ewvj%a`ZhNAJDVsV{38vj;YmsJM$U3C#&Q<(|7;@cWNo3sd+DW@ zs+9k$>tAhJf=>ZLk$l$d?rAJN@~|ns@LU;tw}PO3UJT~|;FDiC9#7?(Hzt$GKh|qy zCIR(nj~z7ECO76HC++RGEu@%LMpSX`RE$65w5u+s7J;E-9<(_1$7 z(}0vQyeN0{qAa3(qCc6^XP(L_El-)pKB~{K_8Gw=b2DK8u+ch5+5vWoX*gCPEOs_D zr1y=FGp+AGu72+6lRx^gj*lc$oo)U7r-kF=v3vnEi-YQMz9oP;z{w>lUD2VW&_=5f zD4AHyq4OJIaoBYGYs>i-p2grwN@2nvVE>`CU7jFtc>+OT0gE~<35-cu=KEorON2NZ zA%^cvmxIyaSTp+gfu{D8zqV{~B0n)vd~VA-F932B&&t!-8^H6I`H=x4Q>8{kjB6Tw zI?|PnacQ*+GwoP9A3yOj&WrW4jjWq16Z+VKacz%IdNKm{I`AT#<`V}MI4?2^8A+K+ z8H#0<$rO&T3~L+c^U`+Fr&Hg?=6+`_1*p;KP6YmsX7?fUqx9IrX8ehVO<{N-zy|?Lkg5~q9~A(OiUTVnYR9hVsD^BAu~d!2djYf$h1nfKp;(0Y(&OSp{&1u45)xhFxulPowoPt zaFwu50dzlTqQvz_cK>;;(p=7CS1*i8#Kg#z+%TR9N?0&YWJZJenD7^+8kc6fIzL(% z8Y-db+&oatrikoSKV_ca@+n_XHoq8cCj`2A+dnq8}6HOf9mgAiNXOz~Z zFaE`5V-966z-_nPW^TUuX0|rskuRKn<|nXB_Z#>c*u|w)kDJWH_nGnSoB3_HSPZ8D z;#EMb0+8LDI|Nw>NOxN&gG(u4B_+jdR5S4bH9+udlc#wuNK+tt(YpYfm`y_>Wp?2! z08fuinCFIYEU> zWBI(iN-@8&kqRK}x%EeTHe_?J4|jC#EOjn0aafu-ZyCqQQ*TzIs>DQbQ##0>ro)%1 z!nh6dm&(`rz$h_fvz$On8q*Q2a$YG z+X(PEH;XAC{KLWWT_x`LP`F>XTfmSXm9t^~&K~~v`!bVZU#|Yv*S~Js7cQ*Q72{!e zjaB{=SCrN~V=@oiWilIH0aKS_K^?>o9@$z}uk_-uu@l0Kt^wLHb}}eqbtPko$7jK%pS=3=tIN+nf7My@7JR0@b5V1C z_jXgnw*-Q89cNmECkhBxJIqArZsCzH#B*>kAM89roJm!LWf|8ayBPEGDJ3v5~Kr?|x0N;EnV^ttm$d&4g`S{}2Hgoa9#^sr8 z{v-XvgSjm@Xa~?k`~nYZ$m8OqBON(`=+n^`v=XbdLF#sC$J!%qC4u5*8r#Bj`c%ej zuR7*4P19+#=t_X%QW%zJA6cHhA7**R6&GRkV)@z&NtJP7WX{cM3UK@|i8v)Ht`f6W zw&olU{I6}D4L;=(jexuEy36eB?G0|a?mF_0IJ^dU8g?Q78X_Mry|xa@|86t>`dS>3 zUo^4SHWU?G!AUOSvCIzm!;*itHW^1d%rfH9n9u0=!7@{HWQx5WUafRNL43 zu?f)1Uy(n6qHN-&H#uqqP}!?tpn0{5pExFySx6S=D5BBB_h-@o(AN5$U}wq0)O$s| zK}N#S0LZWU+3o8uZJoDzX;}Saq0oTpij^JOBn0 z)GBUkk)i~&x zFTL@4Ec44d&G?!p%caa%5I`mc_y`zIa${FSe5p(p1cxdAoYbni%M!UP?93sSdnAcX z*ZA8?t%T(!z=pa8Gg04co*5c1-`mrZ>&@U9fK}|O_*KbM@%wlDT<{ZE4(qeLtIk#+KuoHLF+#Yuu^9<`UYIY_jSPkjKyzkmvnii?%8J2K`2%n6 z+OY))_zGM@8t(~UPX+O*!ebBEc)gfsJ5zySn!+(WRnD(h>(F+wy;Rs#_b)=iKo}0jnI)ZY~saa#UP(!tuiYmG)0(X!H9=erU|W z_5!@VVME{>0$2rD2}9tUXysSR@4nMEejf~hRd^dA_aRPRPS%sjW#MI?s z^rVINfAg}7J5Q}kU!TNA!mxWMqypvvc4o+=aEORjCx=bq)IzG$$V{`E*J^3iysX$d zK)Z=)rHSU)DN2|K7ZHoAuG7}2c@~~Z%}FO@upllrRO&*Wl0$G3pUtyXaK7UKR369h z5A7>7v28qS-4U)jumclVCnK$wL!kb+fE&g1)xC{6mY@xG=+RMMDEjY~&* zGtR2$Plc<+%Q}6>e5SEY^x0;%N85;?IKn9`;rxqb7}tD-^?hVdSs#ge&P^Ky9B1rT zUo|gs8p*_-)%?F-CuSt!_kQp9%;&!Fh1eCBT}D0JzI<3y6LBJ!2;wr!o6yMAUe zkKAX9!-M5`dpq9+6pr$D0Uk^FXIr7aDkmAA#__lM0G~O>D*;%8Xu=oIcER#^a$moB zuBR7rr|LcJS|dQ022|P8C}5aMzgF?9JezWvRV!H0mKk&GES+|qK93SCHl|V_xD530 z->-W7xjPf}Kkw^Y^t|a@Y|_oGCWh7W5W6#|L}_YTN1szr|0ET4NWMG*uwfLlX##K4 zDk&BhfBiJM6QR*r$(HGF>$I>8YnK#E;T28+G@Wn`D;2*ysz9EEnTIN|8B&%8N~L&i zxZgD8M$88nw0C{`ic2qEx@7rT0OB!%3A|R&h%KqS80RiQUVOfyI|cn)ZZ?2(K^vkz zl8(7!$Mn*%rqWi1(X}+So+o3RTITVYh`97p{PeX>1n1ldLIKCe(i@C#v_gOcPGRzr z{zWhh%wqnRcFx$(t+(E4@NM_t?X6p*Hf-wa>6{0}4~qVJ>7C7;nLBPXnS1XrrJg-u ztR80pMq2BuIo9izBv&%32$kL@NRsy`PSPprDLL)xaiQ_w?qXcV> z0ImS3A;7k9KIoi?+J>}a;iL-=k%sAWoK<0~Uuz5~Q~8SC4=clHd7V4-{kr_HYs#E= z98)0T8Os_GFWN5oGZhrqI(Jng*Qz+W_%m6|}RyKqyBmGMj|y z(6InjXju~#@21w^6uHEoxF9?f`#YDhxeKCV1KNP74LxG)WIr%U1pEwmtb?rZZs>C z54bB%TR~roYnp=seoX-`hGpVaO1NC z_Vn<{Cr#n8M@+eYUoqC+p1>LIXgmlE1u0FZu%dHgz=*XIBsEHRG4`C0QpOvnC>vSP zSbK>!4W&dTJ6SoEb3yiQqXIk!2;+DSqCQb)29kB=>3w76`*-ZhPmE`HvqBjQZ6vQ} z>5U2%Juh9o)VqI;6OLth=?x9(ua~2wQWQD+Q&AF+^k+611KJ1eG>O2;!Alfb&-geA z$Ncb?XP$a%<-++7T;0|=uVe9wWywOpX49?^%6tN?vZ%?cPAFjBr zb-@+?<#$iW&9!z{!1Me%7}gRtTp3js ziD20l(22{Y^@+Hdz>V08coX2EJw2tK!G2ZVML^-KmS`nF@Ai53&#)d~!nhg&Y9Oc~ zphf`ooyuQMHoXu$woaFRk1f`t!^X~P=jrnj>uTTVXdXnCap~W-^_@R^eAScPqvLNE zQ_UvXG|wdB_(@bo{04+`VufxSJZ zbD$@7ZBzQHKfV0Yk1bfV@r=|U~}f;ay(_{ z@hs*4=^TQk;fKeF`*hVTTfKZvGK5K-tg(Y+(^3RU9h~Oz7e-$Xa`^UGBfb3~E;a4yOEpYHFMc_^H8u_*i}3 zRobh7FY%qhraI~~F$fB~URk?m;~N{+59Nxvuzi6^wzT6sy+RP;y+J%Pm)d25AtZOv zR&8?va!K8_&Q{5&gftnxEyDm2cyZ1^;&M)LR}w5d3n>l1e5z(+3s92Vl2I*8Ge$&#&g zA);-R`VV3J`G8l7<7SJ5;fD13c*+dL>df=mGTs6hEKFp_NyGxyo2iqy5X0&(`l^>Fq+|qFX_sw-U3f$D7aYTkef`N!Vp}^M6(IrzlduqtXj5xFERT z#;?9~kui2Jzy%kWGtNBIeDJ~xRR)-UJvNxUw6Tqk0DcpOz?tUBRVI7yFU;76bzuQ7 zB?b6G4i9JH5+>y0Bn-C!QTqus4c za}J2KtY1%*tz|3&>PcBd21Pi*zBzznnT3`0&Yx9y4UtLBG#vvrTF2o)og@6wxT(T>G;NwIJ9{Y*>G}#Uv9Xv& zoJr15x6Nk)`BvBzK4CcB9k;o#g%ub9k@$4-ziq&j{+@HrIcDef?FO#`k|^SySodn< zWsPmWDysl|1i)1QD*rdu8h)}hXl}+)z&M@N3N8|^;$~R>u_4EF{H@B6slkq7hZ#-; zN|>!-%setMWL9-|V__t#j{@|oKveX4x372qwLbF+S8D`Nujxe@E0fjv@TSgD_|G<{ zo!540oP^;eX9i5>wJ@Hod;c*fK>+O#^j`;6Ouxc zb3k#)#Mg0_+3c9ynL!!Z}$$fV9)m0wW-*Z|M!)b->`hy$!7q9j|LKW zhoY%2k(h0d2BZsfKXVi~L<%^*CbYauUg5S{UX+|!&i{wl>7xO|9e;54`RAKQAAdZe z)waR@t}8D%?;F@5@U0*-0p-u<|F@g5*Ix?r`H9ffW9L8b{NY$P3UV1=WT~`8XgzcC z&(h=Aj=$i<*~hVRi5~?B22%Cr@rj(dckkZpp3Eo}xflTGI`91TF2B|Q;64C2eY_ku z@yEq12LyhgtB_XlLjN@>dmOsb?2t<(^uO;(@7qcB=r zeIik(Fj4z7Lw&Ya!@`jefiy0_oAE@fluVWJ(S>qh&rZ|Ux653aj$Qs|S6p^o=aLnt zpcFo4SuWwV%Os3|1{ednIS@AhvN=%q1?b)Y&J)*o@maA~JEL=Mjsi1B0iPEtQx)ye zS?hxPw-5kQc$V@1{tZ2Xv_A3dqAz4N>z z_65X724KL!T)=B{ZVqr73&YEVVVF*mxQbr6JC_NJLIUC7gbM`T;;^`E18uTjo+(n5 z;E?)V-BQlx+RnLjZIjd^X#jFflswl7g_HHTsAH^*;Fz_rTCoxk;EPJwADJ)5`gX_W z;Sl9(Iu>2?->$mceCL_q(QP}nZbFF+j}wLu4oA5Vue>7SImJ#3m5$jo26Un_-?b2- zIX6dvX{LbiLR6hWYmzVQJoEgoZ9Ue0dwYA((a{mCTD7W-D>UC)8UDF3 zRp$Z>;cGyxH~|oK|I5<0tsS{X9x(Yw9yEn*?}mjCZwsXAqelRclMoktOaj6=dd@mo z=!>NzoD1#_3-3{vOg%PI)-^VpSHo0z$DY2z13PwRaRLDK4_~F=QS80}z?Fd7<$qlX z&{YD3KafGd$;?ZgAJ(*E>Qk`KcBe#9pNfbV4#W!!alH4Av+;S?I{1U#J0HD$WaQRu z$<%B4jxLkLNrEw)tQY37Hz0COzY&{A2p5m?8JH{$$=ZUdd=EAXMuAEhmZejFG920_ z^&N~|rSQs1K9QjwhIxq-g1hKmN&rG!k@mfb`WB0?rw|5R^uG9cI#;o1?%qQJ{AIqgt7a(GLT-JRXsj zF+SV)UmAAof4CBm8K-WlPyx#SeNg`Y3Ta=*7l1m(e}0=8`KMb=X8pQQ-U8s^Kk+z7 z6q!*d4WbDhg}APvUN{Oy0SnJEQqJ@3C{^Pi469S$!9-2)aYz*oR?`8`WX-Z6m*T-l zr8RX()U}3fNTRQN39=`QnQ0N_wTynnYJ(A-2Azv zixZ1Ycy_8-GP#jK%-u3(Ld`QH#m|j#oGrR7*DjySr`Ec ztO~T?^}ov(F1_?Smt9i$K`NDg`jxfaK-q&elYLm9iq+xGff9}qD%dZ7XmzZDD+2V@ zaSWJGr%mwlZO+{990jI^0?}O4$*0xWxZ~N%46TF|Q0MI|;r~jrj!mepuFjlx+G(-% z>(_JnSy%MTa2TEoIq>U9ySa=z{|uh}XYRQpEbi+q1x?NI0N((JL2ekH{D(V#(37|S z_;rh_N=eE~xC;FdXP%@=zzu@JNObDuADTc3$hLVBN?UEyCDSz>{eZm056VDnat}ar zA|8~mnz{~W(mjfUfc6Xzk$$3gAXkfkBTdx^psz-N8U(8F6-FNc=wpBizRKz<+vc|q z(W!N_-2hrq`xv-hq6@HA(&f zn&G$&1z`lx4v4|=kq93R7`!^z8jmNg=vZ`F$7!dWye^mB{ovbgt$wmtcnVbvW=o|c zK8IPCf&j>uO1#ror!CwTZ!7B^_6o;lwk>AkJ5a7c<2Fjm`CQ|;HF#HIhB+8aOPI0Y-alFO)N@2G1{-*1uN2mXd2>@rjv;20-*_rE3B7iO995EIlofYgS8b3EKzHlT+Ox~+b-8; zmt%qLOmblW3+q}_7>@(+Sx=kE!EAUUB)&7kuEeS9W$?j&hy2 zf)YN6g~I&OARiI%BSSQ-_&9(Dqdp4YV*$<|HcBr9#W6nT<|r_g6mWCQ@uaKClbkiY z=)jc+Wy;zg@}uN3&$}$2AxG1YEolyw<71m<>#r)$BwNCjBOW^IOIYw}x?~=kpF{#* zw8MsAV58zP|KH6S7^6BQ0nE@nfF9m#}%Az;@k@Jaxl z0|e>D=3p0&p}lV;Te`QqH#?EVy8)K4Brdf&C^% zT|jJ#-SMy_KoXEB9A)~P<#amgvt5(x+u8B@!iDoL>1yw2 zOBAv}aU2FQ_RnEy0H5EH?XGsK3-NNMlb?OZG&)U}^)Y~HYbxo05l}5*vACG*;i1^{b3v;fHf4%!~Wi&zO7`IH?)~} zSI6nebm9x0y)CJ`Hg8@H1OvHJDc#xJoE*qxaMGZV+}HjL`%43CEH51!*Z3NG0$|R~ zQQ#O+fOE{cgU){kqnxR{=0rZGEf@q5$Crvy{Ms_p!~a!Hc#lYJ&+%o^L~!bFMdAn3!nYmr(oLux*4CiqV&o-lldiH16cL2DUA%3V~tG#o&)$**`Ci# z|J_J95pvY>&vmP|FLuZ=_ z!LrOkjukI1E+B-q|F)166L1ve(+SB$ka&n$#F0hFJX;DOi^OY}R4GqCpp;Ee-Pj-Q1A81LR-aPMppN=m$sc^@$PdyC;1NcZo3YDa> z>oUyQL&aH>)aHD6;y4Dpq)j$y?stv?Q%V6l*C@yjVg7SwS{-1w%m_P?>jeuR2&1ht z%>PG7Ew)@7&I85{;6e!HPo*@%#OJncJ>}fxD{g{%|FX$UTwGeS8qWakHsjAdRW6MT zn|Ry27?uhF2|C&(0KwVBp~THl7G@%=|*MzMZ#MFig%+z(}JT@LdeJ0 zM#jwD-TTVx_w1INOLV$~lj-obxjYx3B3DCz%AJ?4254NBzHdC}@-^ioXRP`R^O_NN zJQ)B=ASE8}LK!AuIYD_xikAR_0*(+&_l%Afwq?dP{`R`p3O~H@hWu4sOTXAwF1I9i zZ#TJ#iID5#_~5Y9-BgoqVgQNf?8LYC`~VR#fy$6t$)tpnDisg &}~0Ysc(VCI7@allhmIdKv<^VtF(Cs-;aa>Iimj|}R< zi?9t%O{X`Uw)_j}hK~ogJ^Bz=0>%KHgz^{cI2@ZDz!FOIEI`&9S+lKFehI4=6BwRz za}+q%6tMHk&93*H|KvNL*U%c_L-Lkz&n)2oBczb)7~TiA-&zM6-i4Z%cJ93JoFz+c z#sj@in*M>)N>4v!l|N4ZDUFW>u_mnj^CJTIA`ZYUbwoz6v^blla!qI@bW`Xm-X=Y@ zAbrXTKd$r^UjXo9Yp~_;OA&*T$6o%`jK7Swv;i+q!%wqXY%JeYj+y)R^@ppvcjrx5 zqN1l>DM0x%>??a+`scF$WJ~`v3e*5lJjA7j0Q;;Lf-@s0+4tkoDdE(LqA%7OCS74H zm*YSQ%*5tR?|$vkC+>MEmcD1KYw1v;VYTAbOn)jEpE5E+-FY1M^qzP9uKePhF;TS~#YVpF?G)nW4Uu!k~_6NEK@d2jEcQCjb&CFtVt zm@ZkGFT=%*N)bDbEMpVNMT!@tEuclhV&WuS!w$EFjS>YP(-hX?v|P%trn?ea(6&Qk z4mX7d%W&f32oTKvWUPeG4}u!S;_!f}@9Q>a1*Zc=2Xf=X z`FtsdPZ7c>ph3VjL>dE!Y6t*y&dpKa*iztd=Rety&UrRM4if%wJn8@>jp+o2Z$bQ$ zHZ19aNdP1G!{vY1m_zpBao*E}CY!}>sBD(Y|Kpc_@)HZ*>L2*TdCQm65cs0mxT&dl z7hVIn=jUep&DTn0l!&#q1+jX30SKR2<*UF#L)$s&r*>t!`!DsOa*=0BX0}WInQ9Xi zPU)-Z)r7O**DK`Z@cg#*IxYM8*jY+lZ_jm*=Nj~01r!rLVXg?&2X4N zfRmbt!@v9I7${!$RxbpVkX2M*`kb4iz>!b@^UO`PL!JK?T<0h1bU}Es$j7K-_b5*j zrkek~RviK{_&ASpkIIHhDE`%NfBTI8@F#zA?TY5+&&CUd^YYIsZhiT1F&yi_LApHX)_8URW#WmEbjs!SQ@ z%gP4y9L^3(^SxTL18c7xLwa%)8)%L~}CPm@O1=phgL0#agD%i?pW^K&O+PzB*|LB3|n>YtEme zz+q7UjNoshJesGVT3`3Ec>ln%JU0G~-F>^szW6Ly95St;!Nj=n532^i>^kk$F)R8%#qv+2 zAG?n)rh)?XNvx4Hwwd*%g!y^*?(#!hwiHaso&yY^TIEmWuF9VNWcvUnTLJLz{#725 z{(2!ebMAOG0CWP=SEouwR{;#HxBN(TXySje*&5JK8oYUNVbrU9i zqHj+EMu7dW01n#6u2_tWqPM7RT&sa^6~2XXx)X`AfZ##x$IXgIeITI3B0dTgnG(8G z<-`r=sQ`(Xlird^SVSxX$!A>K#GnI^_A#zbg(WJryq#IhA8kQ~o%ztmcKKOSpymVJ#_pY6z*(_hXXy|HfP4;KASa0Eii}ZqzVRWM) z$3j{SU&n{dvE5>*l5b;kzjG8gbP61k`LFz_zO7!kNP^YrNSZ4Ce~*51$sbn?PdLH; za%YKU@rWf8~@^C#@M|8 zL3?{FNY#PW@lg@5A@Ec>3dx~;Re#240SQ4FSE=6`dXb4ISw|)dU5Bx;8E;9Wqe-j; zByjVy4Qk?^-T`y()@}G4Ku+)6We)(V^H&1&Zr?WuG|W7GEa0yM`1=5SL%{WM<~_M< zp7~}RQ44gY(67DJ0>g?~sen6ICI0Ar>(;(>%g#N&*izU0QhxCYlU%UKz&;KP&eY}P zgFck&U@Za^>Z`~h3+u-{{@M?b=F!(OnnvKNu=G)WB0O4#ovsaAd!zy{bwoH_yNStx zRO*s75ZnI%!Xj3RB}{f~q?F&=T~77wG>fw%b=P)veDZ&M>Ysh0<&5{QAQH^@{I22Q zA`F29ULmZ*l?GxOn0nC=;~ev^>PA&}7@%`*jsk~FfoQ5LPck7&6kgKlru-sv-hou+ zfAuu<)Aw(S)>WNT;l*lP)lii@Y1bs}sDbyI0$GM{`sS%%sBFq-TzKKaAKrQQ)t~s4 z&wZ{dnZ71??e&)I9sk>mVB=qQ36y65Oh3=QbdZ1`YCW2u+7I|uL*xcXUUF;tl zAzgLTUI93C4}cm0{v!cj;ZL>#KtqB$h!@=u zC5&@$4R*EjySY66ZsN{g-u*(uCqI+^tuszFr!I|u088I7Gtd_l3k5Qbl;O=eomOCD zF3vcTV917t^AELcm7> zDH9=gc@B|y`0;U9(4an^BY;mX6><|M$c%)^@sVIrBG!1_f+e4xcf&`U{^zMDKlJwYYb*c7 z@BGebAG+Xz3tPs<7nwEBnsI#gFSB-y$?w|}2Kc^ufM?w}{U0hw9@(LtipC*CbT;)r zY98o&?BpLXS;Pq75imXoPzU9oNjI41vn6w9cTe%v-X6VsKhT}Ozx+ShV*o8*d-q>! z1gJ4kJ<2l}JKhZdl1_Qlv1Qe=GY0@i;go|EJ}uaoOeQk99F2g{pWJuXnq|q)cYSd| z$H`0QE$mET>AO5OjF0Dp-03bHXD5!#8z$}N{EC&eq!HQ@mT+M|eUfa!jrmz&b;t9P zhOlJ_*Depv=6l5ill{>=iySb*@Xn9mD!7>>0s(*&7Gc00$4H7N!Xn-$PIPZG^ULMt z%NH%bsq?&ZTAy0D=*9cjzO?C;*I(I%qWw5kuGfW0h zreH64DN|ID5b1MnjsovV0iEMIdHe#JCux{zhc^EmhDmtL$IY;UsIO_t^8(LIIPv_j zO|AlUNs-4Ddp-g{g7S@--`Uan8{hiYvR}LTE2phozWnt1?(Vw6s>e<4p$AO%?F}YB zJ{+1<(ue^-XED1Vl(UHVrUr(IXyHE!m-6TtxRsYk->qP1 z5ZQ%kaPCJLk4bcv0eLsi2@Pk13`I_gBIcM9MF6X_+(JcFAYGa!9R@Bwg7i!Q(P^`CWi zJapR=kF5sY!7cs$GN-WOlIDuQ7(ZHEakh3FXEQlQ93Sa|^J`j-)HydtfypTlO>s=$ zV>bU~Hewbk+gWC@33j4R9sjd#*|Cr6^0{0%mKjrJVlKJrs(Ckm^S9b=y78tZ%NiRO z6*sJp597Ii?y-kVdDo5-6n`w%+8RK9aU}wO<=~RP`w3R)>|Ox2T?7C+Ce@%0NfK{z zSum5du+6jWl6GPsR5rOL3kZMSOBUL#hJ=H7$DXfxELO%FTg=;u26K1sK=FZ{-FU5X zg0f0(8u74%H!Y0wu3jGl@J^qXJ_6AA!BznDhDVJ66c?)cKEpHaP9$T1bDfSpFA|^g zgo8mR%hdZa&}i1Bo*f$8e$mE_k2armR>#W5)WXI@DoB_NzMx~BjH9>sK&BD^u)iw>kwjQc|glMj~3WQGtu(H`l z8_CkrZZ?7Nwh2+g*l^&o$ZdovFnPoSC9#brp1`RjF;mE8!*KVGAe|YDb+vXZXlS2z zUF(JCwx*XYH@E)XEo)GM^i5y|ri_a_kYIlYF)$agaV+Tb((zFyVa<9WC{9|VkvV^k z0yPxibmm;*uVaO1);fOE62eA@IR81??0PtNr&cJ(MK^S4Y$-(Iv<++lfDC09HU;3o0?=}vw0`k zWPZMPsQ6Etx8#O~;E83ZbJ4veO;Q;Ib4){>J=s^H3@f zn_9$!lM$Ga7J#sNIXNID_+v3dGn#NnA{0ES1V{vpvVqiN%S%2WC5d7W3G^JxNDdJ> z$9zUAm+%rxG0pn&%Q#b9JG?SB4GGASdR=MoQ-Ie5u@hj>q(QHFO-+ke&gFn z9YL()-QGR?aKkW4n)wY4^>KW}1jYabX{9-=w&FCsl43)e?!(r?%*9VE3hX!5U;plR z=P$_SE)I6>xUjf+W30GqyY!eR+~IW|*L&fJsO+(v|KtxMj*wgKb3A05axC~CwFD`c z%-KRI*qq6lcgjH_y>waOv%mS94d3|f-(Gb2Ip-{D+V*ZLd+%Ll?4Dnk{OfB?I5LFK zf8Z0T_+~I){UZ*xNG%<0H|2zr8tjK_yX}$m?jZcne8nTZoudAu)mF?nnZ~}@7NS-c z5CHATd&oZuE`ABQ5qp~&n_7b2x)yWiz-V~u+wbJ}4D6Ff0Ki-X>O4dokFeg0st=h${d-g?-|43UP1>+yIC-MEUgx9+B1ay^R|l zY3^vRuUod{vn%TBy6X1sHpQ{g7&ZskM+2O7m`K(MGhpf=W`FJ6w3^sWQx8(WqWO!M z2ZA!3<4dOS@jLys}s8wMuJQ zs`A>qMgFnzkF{kNC6%pJuq;rNNJ$haW-&qpNs$Bt2oM}h4qwjU<@fIXe&_VLuiu+* zh8SQ5nEB@Q_ubdsr_VW^`h!eXoDu zRkN=?eDEXx`q}S($elTHda+jHk{UZeZoF7bZ{apG`8>JhP$OfwML*nG46c}?-%$zl zO8{--`nP{=n$`!|Q_xoFy~h2YeT-N4^NXIjYSq2&%|Dp^$shaisYl=X*7T8lz7&7? z$!PgQf8p9+d?JolSMjaiVw9HUe;i>VG4{JzAS@m!m4Tk~;`{&0m47K&sas@0a)Io~ zFsB{~LSiH*8i4Q}>L0@tRve|CiWqvvbA@OvU2vaW-F6>1eYSUYX~DKwI`|M!$A1gp zYM1@5bokH4GuA*@3!&R*=asc~lL9bYl2-U8P$>La@eytV;2l}1sY0Q$(rB;@X8(_` zedELFy$3o!HNEHOkEBxjGVX%wZEsRhh+Qfz%}^pBS8I<$G814wBnT#aobej6(5c`B zT>zyx4;zNYK!t;n7hy1H;`sXC8DjpdxK4 zTrDiu3%8oR*1~KmSFgLNV!2!@RqvjB)v=%3|CS#}|C^`2`SH2;|H(!0pr+hiuh*H0 z2)7HSu_Dk0A8yOAPFOd5%rHIn5GLufK<^K{Bj+tx0&EkP7z19@_HR16^(gC#gMEn| z%rG=vSK0q5!?DGNH*vD=_Sd~GKK!%4kiFxPH|6%NtwxPce#EVP?1QfJ%s1ln)~4fU zejQHzBO(fZNs;B9g9hQpmfrL~Ij3g1hB|p zOOh3OjR!>KjNh1_R2aiv<`%T9k1sB}-@CBT`_jdkWGMjA4}TfRruyNs0G9{MPumU$ zm>9$Lyv(0V`E&TW0SBXJtfC1*tl+3{tMs+WOpc$7gOk zc2E28-o1BL3x#qDy|dS-kq=JGXDEUp86k?PZc;+C$Ez46n5~;Xgb{kF$R?5+*n;F~ z0yjz7W{4r^jKfpG63&bVfBca+J=|j{CHDr2&GdjwdLC0n763>L5*On^xB`VQb4li; z>GPDx#4CXofOE`@qStCf@#dP#LC{yL)ylzA>BtXFP49ohoyQJ!@TStK`B_{!EE{Gy zsNre!6eLDsmGmKO*k%lbnF-wn8`-FT5WWHih`e&Yde&P1}AL!gRJ$sE31XkXz&-e6-(DOiCo) z!4~KNNfPMa=>b$whkgO;Glj=mwV<(MGd}#PO|1Ctn1wV+3>Bqs6#q~B*Ox<`7%qxk5CiN082kKX{g3Hy%tr+U3Bq$)cxd# zUHfl8J<%=yW?2^d_{a0MH*E1h||6z*PWS9WWl@ zp1@8se~^fg(bGIPn!Q^U0G6|~i5&{u;Iva%n~qa3lf`1b-fm~{#fbW+PoG&ncH8al z@Ywim)oiAm?lfJu*`#*I=0yYf`1YX(**+BXD*sW=bmt+i~O%wtJUE!fygULu- z6015D#55=m^7FiC!KjzvblF1}+={Gt;4B{UAgj zr?KL~)4Qe!2w(hYtmadD7&h!5#2)!>wi39cJ};vH$Z0qi5|oEs{!2jwFd?M0_bLv9GTGTby7i{}L5l;$ReX(jy4;TrvMb>T!gI zj66Bgs7?i0niUOfQ5K-Y)$eduQ&<7WAmYu*&gUVJgj)G`{^Y4&tyiviagy@brgmm{6Uy zXt-bypSZx*mJFYwDhCM_9?F?`KoA_=Y9MR=3!(l{17H^?6v3KhNh`4c<47Yxj9JjY zmw!UY$rWjcDS?_uPeBO(1zicy3rP=X2Db}gIkUU9=Ax~2+{}@RCNr5k@5$wl{KTDi z9l7td-&c8JVScl_y1FLZabghVpN1kJ2|`3XEC5Ey183qMh7X6)KQcFO39x<#%w-e+ z*#f|-op0G7Q%d=z?|Qd?-;X)cv!_x1FmCn%`q-B78)Su@h0x3Pe*{vI#wq|e{?mB% z2DAPsE);p>Us!u?8jrBMr2qem_rBwVbN(9v#0Tz3247c+D#N!jL z0#LCCl>sKh9yrBK`-U~UT^V4(`;K!-9S}~#3X=h)n9JeLs4mL{AINR5eSBqo{muLK z-*zBhyc2s%I9gcm;p;kRV)EWQX+cMk${wzkZ;$j6BJGoIg=>^_(+Gx;3Mz4wlY}sw zLkXb_7Y^R5FtSMC5+c1va7m=GNL0j>C_T)3V9CFaL*nvuglojYr_YTpq)P*pUIJx; zLNI*18vq8wTHM7eIJIq;SznLFnvLl_naur%tL4Mrf6u+;!*|_V-RkzTi;MGopO76h ze{^~}n=Tept#(_!=0q+#JOB+CjZZqMfNn75g>8jpZy3I|BE6(UKpupk$pl&fRWwg`DfNNU&x{S zUw-_Pg3xhD8#PvS3s4LlJ_~pzTXKKB-R}MIxtZqK1zZWJvv$thP52WQ3U>;83Vu@n zObM`60@|cW6bZO*df|^eKxw))428TI)6lrQPwkEUiIv%|wOSDms}-`@{8qEsaTm`n ze&tKqvq$c_%jG62t}?Yhm0DkP^?Du6jaTYp-3cw0vu4=%)fs@u?VXfANd=>$Lt8l9 z;s5|nz@-Pk78L3iUfU;`7==lyIoH=22n9(1Uetj#EI(N};bC=x`t7y^+G@sbaK z>QT1|D()YY1;m%5>>WT$)%nt4v!VDFSQCcPiA8=KylJW%_5ttsAEYNDmCouq-2u?ym8esSF z8Gs?fS{?(;9WVq~S1c|GOOVXbXKj$cW^59d#HuVs_=h-jlMA;`;!GyhY1CY2ZN+68 zbysY+^5tf2YATnx_sws3W98nT{rTJ%D`WNcx1VO`qXOWt8iVA@dxUAcSBMD_-aase z$FnB;p@*b2AzUG&-V_{>wPQmuAy zV6%m5o~ePG7S4KP?93(Iw8IBp%MG347RTu4rY`~Cvb7PS5x_4^0YCEpino9C@_xrg zaS!yje(^K0mKTqMq`$cS|NhLc|B-Y4UH}xy?kx)$7&)l;0S$^k2Cs*f3PrbGo^YRO z^m_mK%!SssFPx{~r_h!y0Ib|nh*O|bxN{qTb|~~sF|aKHhM6K@s{zA`z?H@xkl!5U zR!|0pYr;AnZB`-;wK_YHMmycc*M`v0AoSzrymQaKd*(uvi6WeHJNC9?dnR3Fa$h>N zzU1&tZ?rF&v9hy%cn5;uM{5sG7O3me%tX9-A4)4m`T%+?m> zL|dZ%qH#zlTdf%HFdXq->-Nuxm_DW|NQQtdsgkZ;+W)V4{xO!wAPI}FQDO@qs+7uZ z6RQAEK=}W`sk7}TPoJ_?fG$=6_(@o<1Q2Eq6#;uFI1F_~usF4hU<(`hN(c+u+t$BdCtJVG5T5;E)=^d8@?yH#awy52Y|MEm!ZTj*Yt_ z-q&@lderTpjp1wndpqXx*0+V}m0E;$eqi8V1`3^%i~o`oF_n@!B$YyyDW*R$09Y>I z;9`N7y$J?@o|ZPi3BGqt_`qNW%0Q~uYQ?>^ zRhQb_h%(Jurcm2Dbge8uCN_|tzgsjK$cM6IPE{^4wsbhtOWyPeJ(q&WY2lzd3ml0$V=)*TLpt8#6Nsa(g(tw;4Wd z9{RIGfVKiaWq@I{O$jiC!V~~DI6g8Kc^lTvX>PR@0BesnR9Gd3wZ~;6hEsiXXh^sm zC@S$Qcq`6*>))O}m5M84txU1>BX{9jo%wVIdr}QtLK$Ogz%PcQp$^PO24a;)?4uY6 z@B^6Aa;D8TCT-rk0T7sY)sx6{ZI56<_CAcBWTBA?0YiuYjne1XOfHi9tME6~HS|jdsmNXP&V|#CP&%Or^ z6wCKL_8Y(ct#7tkPyd@weC(;#M?W$HCR7I4cGJyflkTu{nug89+??aZ8Hm zfeA98fYI-bUjoujrRKEy2HWk8)BdF-`|TfIYnBZ0&CrLl@9ehz|I+jCM-18j??pu{ z`)^_9|2Oqs{O;#Zw?2F7gb8X{_Qxe;oV`;l>h{ZxhcnwTWtlvDr?yGJ#Y|=8kI`L5F8J) zGA7%@Y!n)T?6`9}>e;A_GoSG`KZUGU7%%_`5qrH+!^R)wW*-I?LL)Ho*hnF8QV710 z*y6m8+GxRAk|uFkv$c2y*Qe2vYB&KOiA$0rNK7rU1_+JZlNohlGfJchm!9C`O(<); zK8U*m@hV_#)5WVxF1@mnAMbXL?k^S|K2j+idfTyka`(UaE!Dz9uP&araJK0-x7b

    >Nkp2i(9fWq{Dj%#$w$`9Tmn`vNwim30l;~{ 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 literal 1054090 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ⅇ{< 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

    `hph~FrvN%A72aitod$(VWuTlSZZf+G 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

    K>i4Y-)+ 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

    =td)`xXs^hb`P5S3nd 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 Y@ju@ELx$kze)gaI%;$dUU;exQ51zyi8UO$Q From 2462c27f05618a88f6a206b095096c9cfa0e83eb Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 8 Jun 2012 23:06:54 +0300 Subject: [PATCH 340/433] Comment out fromPath release until I work out why it makes Hugo's Tomahawk unhappy --- src/libtomahawk/mac/FileHelpers.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/mac/FileHelpers.mm b/src/libtomahawk/mac/FileHelpers.mm index 3e3c01d27..b8a0f0cce 100644 --- a/src/libtomahawk/mac/FileHelpers.mm +++ b/src/libtomahawk/mac/FileHelpers.mm @@ -203,7 +203,7 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]; [self notifyDelegate:dict]; - [fromPath release]; +// [fromPath release]; [toPath release]; } From bdd809cc30accbe39af4a0af86beb81e99e692d3 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Fri, 8 Jun 2012 22:16:50 +0000 Subject: [PATCH 341/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 146 +++++++++++++-------------- lang/tomahawk_bg.ts | 222 ++++++++++++++++++++--------------------- lang/tomahawk_ca.ts | 146 +++++++++++++-------------- lang/tomahawk_de.ts | 146 +++++++++++++-------------- lang/tomahawk_en.ts | 146 +++++++++++++-------------- lang/tomahawk_es.ts | 146 +++++++++++++-------------- lang/tomahawk_fr.ts | 146 +++++++++++++-------------- lang/tomahawk_ja.ts | 146 +++++++++++++-------------- lang/tomahawk_pl.ts | 146 +++++++++++++-------------- lang/tomahawk_pt_BR.ts | 146 +++++++++++++-------------- lang/tomahawk_ru.ts | 146 +++++++++++++-------------- lang/tomahawk_sv.ts | 144 +++++++++++++------------- lang/tomahawk_tr.ts | 144 +++++++++++++------------- lang/tomahawk_zh_CN.ts | 144 +++++++++++++------------- lang/tomahawk_zh_TW.ts | 146 +++++++++++++-------------- 15 files changed, 1130 insertions(+), 1130 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 15a2091f4..55303b1cf 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -471,32 +471,32 @@ connect and stream from you? LastFmConfig - + Form استمارة - + Scrobble tracks to Last.fm نقل الأغاني إلى Last.fm - + Username: اسم المستخدم: - + Password: كلمة السر: - + Test Login اختبار الدخول - + Import Playback History استيراد تاريخ إعادة الإستماع @@ -1190,7 +1190,7 @@ connect and stream from you? - + Latest Additions أحدث الإضافات @@ -1210,42 +1210,42 @@ connect and stream from you? سوبر كولكشن - + Sorry, we could not find any loved tracks! نعتذر، لم نستطيع إيجاد أغاني محبوبة! - + Latest additions to your collection آخر إضافات على مجموعتك - + Latest additions to %1's collection آخر إضافات على مجموعة %1 - + Sorry, we could not find any recent additions! نعتذر، لم نستطيع إيجاد إضافة جديدة! - + Recently Played Tracks الأغاني التي إستمعت إليها مؤخرا - + Your recently played tracks الأغاني التي إستمعت إليها مؤخرا - + %1's recently played tracks الأغاني التي سمعها مؤخرا %1 - + Sorry, we could not find any recent plays! نعتذر، لم نستطيع إيجاد أغاني مسموعة مؤخرا! @@ -1348,52 +1348,52 @@ connect and stream from you? إذاعة - + Browse تصفح - + Search History تاريخ البحث - + My Music موسيقتي الخاصة - + SuperCollection سوبر كولكشن - + Top Loved Tracks الأغاني المحبوبة الأكثر شهرة - + Dashboard لوحة القيادة - + Recently Played تم الاستماع لها مؤخرا - + Charts الرسوم البيانية - + New Releases جديد الاصدارات - + Friends الأصدقاء @@ -1401,52 +1401,52 @@ connect and stream from you? SpotifyConfig - + Form استمارة - + Configure your Spotify account تكوين حساب "Spotify" - + Username or Facebook Email إسم المستخدم أو الايميل على فيسبوك (Facebook Email) - + Log In تسجيل الدخول - + Right click on any Tomahawk playlist to sync it to Spotify. أنقر يمينا على أية قائمة أغاني في توماهوك للمزامنة مع سبوتيفي (Spotify). - + High Quality Streams جودة عالية في الأغاني المحملة - + Spotify playlists to keep in sync: قوائم أغاني سبوتيفي (Spotify) التي يجب إبقائها بتزامن: - + Delete Tomahawk playlist when removing synchronization حذف قوائم أغاني توماهوك عند إزالة التزام - + Username: اسم المستخدم: - + Password: كلمة السر: @@ -1454,12 +1454,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? أحذف في سبوتيفي (Spotify)؟ - + Would you like to delete the corresponding Spotify playlist as well? هل ترغب في حذف قائمة التشغيل المطابقة على سبوتيفي (Spotify)؟ @@ -1601,8 +1601,8 @@ connect and stream from you? - Remove Account - حذف الحساب + Remove + @@ -1685,7 +1685,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play إبعث أغانيك الخاصة إلى last .fm و جد أغاني جديدة مجانا للاستماع إليها @@ -1693,49 +1693,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... اختبار... - + Test Login اختبار الدخول - + Importing %1 e.g. Importing 2012/01/01 استيراد %1 - + Importing History... نقل التاريخ... - + History Incomplete. Resume تاريخ ناقص. استأنف - + Playback History Imported تم استيراد تاريخ إعادة الإستماع - - + + Failed فشلت - + Success نجاح - + Could not contact server لم أستطيع الإتصال بالخادم @@ -1743,17 +1743,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify مزامنة مع سبوتيفي (Spotify) - + Re-enable syncing with Spotify إعادة تمكين المزامنة مع سبوتيفي (Spotify) - + Stop syncing with Spotify أوقف المزامنة مع سبوتيفي (Spotify) @@ -1761,22 +1761,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... جاري تسجيل الدخول... - + Logged in! مسجل! - + Failed: %1 فشل: %1 - + Log In تسجيل الدخول @@ -1784,7 +1784,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium إسمع موسيقى و زامن قوائم تشغيلك مع سبوتيفي بريميوم (Spotify Premium) @@ -2590,27 +2590,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks أفضل الأغاني - + Loved Tracks الأغاني المحبوبة - + Hyped Tracks فقت الأغاني - + Top Artists أفضل الفنانين - + Hyped Artists فقت الفنانين @@ -2730,7 +2730,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! خطأ شبكة في تحليل تقصير الرابط! @@ -2738,43 +2738,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) يجري مسح (%L1 أغنية) - + Scanning مسح - + Checking فحص - + Fetching جلب - + Parsing تحليل - + Saving (%1%) تحفيظ(%1%) - + Online متصل - + Offline غير متصل diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index eaa52a8bd..d1b271e5e 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -135,12 +135,12 @@ connect and stream from you? Sorry, we could not find any other albums for this artist! - + Съжалявам, но не откривам нито един албум от този артист! Sorry, we could not find any tracks for this album! - + Съжалявам, но не откривам нито една песен за този артист! @@ -187,17 +187,17 @@ connect and stream from you? Sorry, we could not find any albums for this artist! - + Съжалявам, но не откривам нито един албум за този артист! Sorry, we could not find any related artists! - + Съжалявам, но не откривам нито един подобен на този артист! Sorry, we could not find any top hits for this artist! - + Съжалявам, но не откривам нито една хитова песен на този артист! @@ -283,12 +283,12 @@ connect and stream from you? Create new Playlist - + Създай нов списък Create new Station - + Създай нова станция @@ -473,32 +473,32 @@ Tomahaw създаде доклад относно това и изпращай LastFmConfig - + Form - + Scrobble tracks to Last.fm Изпращане на изпълнени песни към Last.fm - + Username: Потребителско име: - + Password: Парола: - + Test Login Пробна връзка - + Import Playback History Импортирай история на просвирените песни @@ -675,7 +675,7 @@ Tomahaw създаде доклад относно това и изпращай Name - + Име @@ -775,7 +775,7 @@ Tomahaw създаде доклад относно това и изпращай This playlist is currently empty. - + Този списък е празен в момента. @@ -944,12 +944,12 @@ Tomahaw създаде доклад относно това и изпращай Open Queue - + Отвори опашката The queue is currently empty. Drop something to enqueue it! - + Тази опашка е празна в момента. Завлачи нещо за да създадеш нова. @@ -959,7 +959,7 @@ Tomahaw създаде доклад относно това и изпращай Close Queue - + Затвори опашката @@ -1190,7 +1190,7 @@ Tomahaw създаде доклад относно това и изпращай - + Latest Additions Последно добавени @@ -1211,44 +1211,44 @@ Tomahaw създаде доклад относно това и изпращай /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Sorry, we could not find any loved tracks! - + Съжалявам, но не откривам нито една харесана песен! - + Latest additions to your collection Последно добавени към колекцията - + Latest additions to %1's collection Последно добавени в колекцията на %1 - + Sorry, we could not find any recent additions! - + Съжалявам, но не откривам нито една ново-добавена позиция! - + Recently Played Tracks Наскоро изпълнени песни - + Your recently played tracks Наскоро изпълнени песни от теб - + %1's recently played tracks Наскоро изпълнените песни от %1 - + Sorry, we could not find any recent plays! - + Съжалявам, но не откривам нито една наскоро изпълнена песен! @@ -1266,17 +1266,17 @@ Tomahaw създаде доклад относно това и изпращай Add to my Playlists - + Добави към моите списъци Add to my Automatic Playlists - + Добави към моите автоматично-генерирани списъци Add to my Stations - + Добави към станциите ми @@ -1286,29 +1286,29 @@ Tomahaw създаде доклад относно това и изпращай playlist - + списък automatic playlist - + автоматично-генериран списък station - + станция Delete %1? playlist/station/... - + Изтрий %1? Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Наистина ли желаеш да изтриеш %1 <b>''%2" </b> @@ -1349,53 +1349,53 @@ Tomahaw създаде доклад относно това и изпращай Станция - + Browse Разгледай - + Search History Търси в историята - + My Music Моята музика - + SuperCollection Супер колекция /Сборен излед от локалните и наличните в колекциите на приятелите ти/ - + Top Loved Tracks Най-харесвани песни - + Dashboard Табло - + Recently Played Наскоро изпълнени песни - + Charts Класации - + New Releases Нови албуми - + Friends Приятели @@ -1403,52 +1403,52 @@ Tomahaw създаде доклад относно това и изпращай SpotifyConfig - + Form - + Configure your Spotify account Настрой своята регистрация в Spotify - + Username or Facebook Email Потребителско име или електронна поща във Facebook - + Log In Влез - + Right click on any Tomahawk playlist to sync it to Spotify. Щракни с десен бутон върху, който и да е списък в Tomahawk, за да го добавиш и в Spotify. - + High Quality Streams Високо качество - + Spotify playlists to keep in sync: Spotify списъци, които да бъдат поддържани обновени: - + Delete Tomahawk playlist when removing synchronization Изтрий запазените списъци, когато бъде премахната синхронизацията - + Username: Потребителско име: - + Password: Парола: @@ -1456,12 +1456,12 @@ Tomahaw създаде доклад относно това и изпращай SpotifyPlaylistUpdater - + Delete in Spotify? Изтривам и в Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Желаеш ли да изтриеш и съответните Spotify списъци? @@ -1604,8 +1604,8 @@ Tomahaw създаде доклад относно това и изпращай - Remove Account - Премахни регистрация + Remove + @@ -1691,7 +1691,7 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Качи информация за изпълнените песни в Last.fm и открий свободно разпространявани. @@ -1699,49 +1699,49 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::LastFmConfig - + Testing... Тествам... - + Test Login Тествай връзката - + Importing %1 e.g. Importing 2012/01/01 Импортирам %1 - + Importing History... Импортирам... - + History Incomplete. Resume Непълна информация. Продължи. - + Playback History Imported Историята на просвирените песни е импортирана - - + + Failed Неуспешно - + Success Ура! - + Could not contact server Не мога да се свържа със сървъра @@ -1749,17 +1749,17 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизирай със Spotify - + Re-enable syncing with Spotify Включи отново синхронизирането със Spotify - + Stop syncing with Spotify Спри синхронизацията със Spotify @@ -1767,22 +1767,22 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Влизам... - + Logged in! Готово! - + Failed: %1 Неуспех: %1 - + Log In Влез @@ -1790,7 +1790,7 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Слушай музика и синхронизирай твоите списъци със Spotify Premium @@ -2054,22 +2054,22 @@ You may wish to try re-authenticating. playlist - + списък artist - + артист track - + песен album - + албум @@ -2597,27 +2597,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Най-слушани песни - + Loved Tracks Харесани песни - + Hyped Tracks Песни, изпъкващи сред останалите - + Top Artists Най-слушани артисти - + Hyped Artists Изпълнители, изпъкващи сред останалите @@ -2737,7 +2737,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Мрежова грешка при извличане на съкратеният адрес. @@ -2745,45 +2745,45 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканиране (%L1 песни) - + Scanning Сканирам - + Checking Проверявам - + Fetching Извличам - + Parsing Сортирам - + Saving (%1%) Запазвам (%1%) - + Online - + На линия - + Offline - + Извън линия @@ -2861,12 +2861,12 @@ enter the displayed PIN number here: &Love - + &Харесай Un-&Love - + Не-&Харесай @@ -3121,7 +3121,7 @@ enter the displayed PIN number here: Station - + Станция @@ -3136,12 +3136,12 @@ enter the displayed PIN number here: Playlist - + Списък Automatic Playlist - + Автоматично-генериран списък @@ -3332,7 +3332,7 @@ enter the displayed PIN number here: Sorry, but we could not find similar tracks for this song! - + Съжалявам, но не откривам нито една подобна на тази песен! @@ -3414,7 +3414,7 @@ enter the displayed PIN number here: Sorry, your filter '%1' did not match any results. - + Съжалявам, но филтърът '%1' не върна никакви резултати. @@ -3496,12 +3496,12 @@ You can re-send a sync message at any time simply by sending another tweet using After you have scanned your music collection you will find your tracks right here. - + След като бъде сканирана колекцията ти, ще откриеш твоите песни точно тук. This collection is empty. - + Празна колекция. diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 1f7558a66..5174091cf 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form Formulari - + Scrobble tracks to Last.fm Fes scrobbling de les cançons a Last.fm - + Username: Nom d'usuari: - + Password: Contrasenya: - + Test Login Comprova l'autenticació - + Import Playback History @@ -1188,7 +1188,7 @@ connect and stream from you? - + Latest Additions Darreres Novetats @@ -1208,42 +1208,42 @@ connect and stream from you? SuperCol·lecció - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Darreres novetats a la vostra col·lecció - + Latest additions to %1's collection Darreres novetats a la col·lecció de %1 - + Sorry, we could not find any recent additions! - + Recently Played Tracks Cançons Escoltades Recentment - + Your recently played tracks Cançons Escoltades Recentment - + %1's recently played tracks Cançons Escoltades Recentment per %1 - + Sorry, we could not find any recent plays! @@ -1346,52 +1346,52 @@ connect and stream from you? Emissora - + Browse Cerca - + Search History Historial de Cerca - + My Music La Meva Música - + SuperCollection SuperCol·lecció - + Top Loved Tracks Top de Cançons Preferides - + Dashboard Presentació - + Recently Played Escoltades Recentment - + Charts Llistes - + New Releases Nous Llançaments - + Friends Amics @@ -1399,52 +1399,52 @@ connect and stream from you? SpotifyConfig - + Form Formulari - + Configure your Spotify account Configureu el compte Spotify - + Username or Facebook Email Nom d'usuari o adreça de Facebook - + Log In Inicia Sessió - + Right click on any Tomahawk playlist to sync it to Spotify. Feu click dret a qualsevol llista de reproducció de Tomahawk per sincronitzar-la amb Spotify. - + High Quality Streams Fluxos d'Alta Qualitat - + Spotify playlists to keep in sync: Llistes de reproducció de Spotify per mantenir sincronitzades: - + Delete Tomahawk playlist when removing synchronization Esborra les llistes de Tomahawk quan es tregui la sincronització - + Username: Usuari: - + Password: Contrasenya: @@ -1452,12 +1452,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Voleu esborrar-ho de Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Voleu esborrar les llistes de Spotify, també? @@ -1600,8 +1600,8 @@ i emissores de ràdio basades en el vostre gust musical. - Remove Account - Esborra el compte + Remove + @@ -1684,7 +1684,7 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Fes scrobbling de les cançons a last.fm, i cerca cançons descarregables gratuïtament per escoltar-les @@ -1692,49 +1692,49 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login Comprova l'inici de sessió - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed Error - + Success Èxit - + Could not contact server No s'ha pogut contactar amb el servidor @@ -1742,17 +1742,17 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronitza amb Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Atura la sincronització amb Spotify @@ -1760,22 +1760,22 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Iniciant sessió... - + Logged in! Sessió iniciada! - + Failed: %1 Error: %1 - + Log In Incia Sessió @@ -1783,7 +1783,7 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Reprodueix música i sincronitza les llistes de reproducció amb Spotify Premium @@ -2589,27 +2589,27 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top Cançons Musicals - + Loved Tracks Cançons Preferides - + Hyped Tracks Cançons en alça - + Top Artists Top Artistes - + Hyped Artists Artistes en alça @@ -2729,7 +2729,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Error de la xarxa en analitzar l'enllaç escurçat! @@ -2737,43 +2737,43 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::Source - - + + Scanning (%L1 tracks) Escanejant (%L1 cançons) - + Scanning Escanejant - + Checking Comprovant - + Fetching Cercant - + Parsing Analitzant - + Saving (%1%) Desant (%1%) - + Online - + Offline diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 165b40118..3aec518c7 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form Formular - + Scrobble tracks to Last.fm Scrobbel Stücke zu Last.fm - + Username: Benutzer: - + Password: Passwort: - + Test Login Login testen - + Import Playback History @@ -1188,7 +1188,7 @@ connect and stream from you? - + Latest Additions Kürzlich hinzugekommen @@ -1208,42 +1208,42 @@ connect and stream from you? Supersammlung - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Neueste Lieder in deiner Sammlung - + Latest additions to %1's collection Neueste Lieder in %1's Sammlung - + Sorry, we could not find any recent additions! - + Recently Played Tracks Zuletzt gehörte Lieder - + Your recently played tracks Deine zuletzt gehörten Lieder - + %1's recently played tracks %1's zuletzt gehörte Lieder - + Sorry, we could not find any recent plays! @@ -1346,52 +1346,52 @@ connect and stream from you? Station - + Browse Stöbern - + Search History Suchverlauf - + My Music Meine Musik - + SuperCollection Supersammlung - + Top Loved Tracks Gemeinsame Lieblingslieder - + Dashboard Dashboard - + Recently Played Kürzlich gehörte Lieder - + Charts Charts - + New Releases Neuerscheinungen - + Friends Freunde @@ -1399,52 +1399,52 @@ connect and stream from you? SpotifyConfig - + Form Formular - + Configure your Spotify account Konfiguriere dein Spotify Konto - + Username or Facebook Email Nutzername oder Facebook Email - + Log In Anmeldung - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: Spotify Listen die du synchronisieren willst: - + Delete Tomahawk playlist when removing synchronization - + Username: Benutzer: - + Password: Passwort: @@ -1452,12 +1452,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Auf Spotify löschen - + Would you like to delete the corresponding Spotify playlist as well? @@ -1597,8 +1597,8 @@ connect and stream from you? - Remove Account - Konto entfernen + Remove + @@ -1681,7 +1681,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Gehörte Stücke zu last.fm scrobbeln und frei-verfügbare Stücke anhören @@ -1689,49 +1689,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login Login testen - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed Fehlgeschlagen - + Success Erfolgreich - + Could not contact server Konnte den Server nicht erreichen! @@ -1739,17 +1739,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Mit Spotify synchronisieren - + Re-enable syncing with Spotify - + Stop syncing with Spotify Synchronisation beenden @@ -1757,22 +1757,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Anmelden... - + Logged in! Angemeldet! - + Failed: %1 Fehler: %1 - + Log In Anmelden @@ -1780,7 +1780,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Musik abspielen und Playlisten synchronisieren mit Spotify Premium @@ -2584,27 +2584,27 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2724,7 +2724,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Konnte den Kurzlink nicht auflösen! @@ -2732,43 +2732,43 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanne (%L1 Stücke) - + Scanning Scanne - + Checking Überprüfe - + Fetching Sammle - + Parsing Parse - + Saving (%1%) Speichere (%1%) - + Online - + Offline diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 54c697a59..5c75699c1 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -471,32 +471,32 @@ connect and stream from you? LastFmConfig - + Form Form - + Scrobble tracks to Last.fm Scrobble tracks to Last.fm - + Username: Username: - + Password: Password: - + Test Login Test Login - + Import Playback History Import Playback History @@ -1189,7 +1189,7 @@ connect and stream from you? - + Latest Additions Latest Additions @@ -1209,42 +1209,42 @@ connect and stream from you? SuperCollection - + Sorry, we could not find any loved tracks! Sorry, we could not find any loved tracks! - + Latest additions to your collection Latest additions to your collection - + Latest additions to %1's collection Latest additions to %1's collection - + Sorry, we could not find any recent additions! Sorry, we could not find any recent additions! - + Recently Played Tracks Recently Played Tracks - + Your recently played tracks Your recently played tracks - + %1's recently played tracks %1's recently played tracks - + Sorry, we could not find any recent plays! Sorry, we could not find any recent plays! @@ -1347,52 +1347,52 @@ connect and stream from you? Station - + Browse Browse - + Search History Search History - + My Music My Music - + SuperCollection SuperCollection - + Top Loved Tracks Top Loved Tracks - + Dashboard Dashboard - + Recently Played Recently Played - + Charts Charts - + New Releases New Releases - + Friends Friends @@ -1400,52 +1400,52 @@ connect and stream from you? SpotifyConfig - + Form Form - + Configure your Spotify account Configure your Spotify account - + Username or Facebook Email Username or Facebook Email - + Log In Log In - + Right click on any Tomahawk playlist to sync it to Spotify. Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams High Quality Streams - + Spotify playlists to keep in sync: Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization Delete Tomahawk playlist when removing synchronization - + Username: Username: - + Password: Password: @@ -1453,12 +1453,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Would you like to delete the corresponding Spotify playlist as well? @@ -1601,8 +1601,8 @@ connect and stream from you? - Remove Account - Remove Account + Remove + Remove @@ -1685,7 +1685,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1693,49 +1693,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... Testing... - + Test Login Test Login - + Importing %1 e.g. Importing 2012/01/01 Importing %1 - + Importing History... Importing History... - + History Incomplete. Resume History Incomplete. Resume - + Playback History Imported Playback History Imported - - + + Failed Failed - + Success Success - + Could not contact server Could not contact server @@ -1743,17 +1743,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sync with Spotify - + Re-enable syncing with Spotify Re-enable syncing with Spotify - + Stop syncing with Spotify Stop syncing with Spotify @@ -1761,22 +1761,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Logging in... - + Logged in! Logged in! - + Failed: %1 Failed: %1 - + Log In Log In @@ -1784,7 +1784,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Play music from and sync your playlists with Spotify Premium @@ -2590,27 +2590,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top Tracks - + Loved Tracks Loved Tracks - + Hyped Tracks Hyped Tracks - + Top Artists Top Artists - + Hyped Artists Hyped Artists @@ -2730,7 +2730,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Network error parsing shortened link! @@ -2738,43 +2738,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Scanning (%L1 tracks) - + Scanning Scanning - + Checking Checking - + Fetching Fetching - + Parsing Parsing - + Saving (%1%) Saving (%1%) - + Online Online - + Offline Offline diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 8d6ccad7e..14b77a46d 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form Formulario - + Scrobble tracks to Last.fm Hacer scrobble a las pistas en Last.fm - + Username: Usuario: - + Password: Contraseña: - + Test Login Probar conexión - + Import Playback History @@ -1187,7 +1187,7 @@ connect and stream from you? - + Latest Additions Añadidos recientemente @@ -1207,42 +1207,42 @@ connect and stream from you? SuperColección - + Sorry, we could not find any loved tracks! - + Latest additions to your collection Últimas novedades en mi colección - + Latest additions to %1's collection Últimas novedadoes en la colección de %1 - + Sorry, we could not find any recent additions! - + Recently Played Tracks Temas Escuchados Recientemente - + Your recently played tracks Mis canciones escuchadas recientemente - + %1's recently played tracks Las canciones escuchadas recientemente por %1 - + Sorry, we could not find any recent plays! @@ -1345,52 +1345,52 @@ connect and stream from you? Estación - + Browse Buscar - + Search History Historial de Búsqueda - + My Music Mi Musica - + SuperCollection SuperColección - + Top Loved Tracks Pistas favoritas - + Dashboard Panel de inicio - + Recently Played Reproducido recientemente - + Charts Listas - + New Releases Últimas novedades - + Friends Amigos @@ -1398,52 +1398,52 @@ connect and stream from you? SpotifyConfig - + Form Formulario - + Configure your Spotify account Configura tu cuenta de Spotify - + Username or Facebook Email Usurio o dirección de correo de Facebook - + Log In Inciar Sesión - + Right click on any Tomahawk playlist to sync it to Spotify. Click derecho en cualquier lista de Tomahawk para sincronizar con Spotify. - + High Quality Streams Streams de Alta Calidad - + Spotify playlists to keep in sync: Listas de Spotify a mantener sincronizadas: - + Delete Tomahawk playlist when removing synchronization Borra las listas de Tomahawk cuando se quiten de la sincronización - + Username: Usuario: - + Password: Contraseña: @@ -1451,12 +1451,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? ¿Borrar en Spotify? - + Would you like to delete the corresponding Spotify playlist as well? Quieres eliminar la lista de Spotify correspondiente, también? @@ -1599,8 +1599,8 @@ y estaciones basadas en sus gustos personales. - Remove Account - Eliminar Cuenta + Remove + @@ -1683,7 +1683,7 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Hacer Scrobble de mis temas a last.fm y encontrar canciones gratuitas para reproducirlas @@ -1691,49 +1691,49 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login Comprobar Inicio de Sesión - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed Fallo - + Success Éxito - + Could not contact server No se pudo contactar el servidor @@ -1741,17 +1741,17 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Sincronizar con Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Dejar de sincronizar con Spotify @@ -1759,22 +1759,22 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Inciando sesión... - + Logged in! Sesión iniciada! - + Failed: %1 Fallo: %1 - + Log In Iniciar Sesión @@ -1782,7 +1782,7 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Reproduce música de Spotofy Premium y sincroniza las listas de reprodución @@ -2588,27 +2588,27 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Temas más escuchados - + Loved Tracks Temas Favoritos - + Hyped Tracks Temas a la alza - + Top Artists Artistas más escuchados - + Hyped Artists Artistas a la alza @@ -2728,7 +2728,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Error en la red al analizar el enlace acortado! @@ -2736,43 +2736,43 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 pistas) - + Scanning Escaneando - + Checking Comprobando - + Fetching Obteniendo - + Parsing Analizando - + Saving (%1%) Guardando (%1%) - + Online - + Offline diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index d51788a0b..28639893e 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -471,32 +471,32 @@ se connecter et streamer depuis chez vous ? LastFmConfig - + Form Form - + Scrobble tracks to Last.fm Scrobbler les titres sur Last.fm - + Username: Nom d'utilisateur : - + Password: Mot de passe : - + Test Login Login test - + Import Playback History Importer l'historique @@ -1189,7 +1189,7 @@ se connecter et streamer depuis chez vous ? - + Latest Additions Derniers ajouts @@ -1209,42 +1209,42 @@ se connecter et streamer depuis chez vous ? SuperCollection - + Sorry, we could not find any loved tracks! Désolé, on a pas pu trouver aucune piste favoris! - + Latest additions to your collection Derniers ajouts à votre collection - + Latest additions to %1's collection Derniers ajouts à la collection de %1 - + Sorry, we could not find any recent additions! Désolé, on a pas pu trouver des dernier ajouts! - + Recently Played Tracks Derniers titres joués - + Your recently played tracks Les derniers titres que vous avez joués - + %1's recently played tracks Derniers titres joués par %1 - + Sorry, we could not find any recent plays! Désolé, on a pas pu trouver aucune piste récement joués! @@ -1347,52 +1347,52 @@ se connecter et streamer depuis chez vous ? Station - + Browse Parcourir - + Search History Chercher dans l'historique - + My Music Ma Musique - + SuperCollection SuperCollection - + Top Loved Tracks Top des titres favoris - + Dashboard Tableau de bord - + Recently Played Joués récemment - + Charts Charts - + New Releases Nouveautés - + Friends Amis @@ -1400,52 +1400,52 @@ se connecter et streamer depuis chez vous ? SpotifyConfig - + Form Form - + Configure your Spotify account Configurer votre compte Spotify - + Username or Facebook Email Nom d'utilisateur ou email Facebook - + Log In Connexion - + Right click on any Tomahawk playlist to sync it to Spotify. Clic droit pour synchroniser une liste de lecture Tomahawk vers Spotify. - + High Quality Streams Streaming haute qualité - + Spotify playlists to keep in sync: Liste de lecture Spotify à synchroniser : - + Delete Tomahawk playlist when removing synchronization Supprimer la liste de lecture de Tomahawk à la suppression de la synchronisation - + Username: Nom d'utilisateur : - + Password: Mot de passe : @@ -1453,12 +1453,12 @@ se connecter et streamer depuis chez vous ? SpotifyPlaylistUpdater - + Delete in Spotify? Supprimer dans Spotify ? - + Would you like to delete the corresponding Spotify playlist as well? Voulez-vous aussi supprimer la liste de lecture correspondante dans Spotify ? @@ -1601,8 +1601,8 @@ et des stations basées sur vos goûts. - Remove Account - Supprimer le compte + Remove + Supprimer @@ -1685,7 +1685,7 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play Scrobbler vos écoutes sur Last.fm et trouver des morceaux téléchargeables gratuitement @@ -1693,49 +1693,49 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::LastFmConfig - + Testing... Test... - + Test Login Test de connexion - + Importing %1 e.g. Importing 2012/01/01 Importation %1 - + Importing History... Import de l'historique... - + History Incomplete. Resume Historique incomplet. Reprendre - + Playback History Imported Historique de lecture importé - - + + Failed Échec - + Success Succès - + Could not contact server Impossible de contacter le serveur @@ -1743,17 +1743,17 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Synchroniser avec Spotify - + Re-enable syncing with Spotify Réactiver la synchronisation avec Spotify - + Stop syncing with Spotify Stopper la synchronisation avec Spotify @@ -1761,22 +1761,22 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Connexion... - + Logged in! Connecté ! - + Failed: %1 Echec : %1 - + Log In Connexion @@ -1784,7 +1784,7 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium Jouer la musique et synchroniser vos listes avec Spotify Premium @@ -2590,27 +2590,27 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks Top des titres - + Loved Tracks Titres favoris - + Hyped Tracks Titres Hype - + Top Artists Top Artistes - + Hyped Artists Artistes Hype @@ -2730,7 +2730,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! Erreur réseau lors du décodage de l'URL courte! @@ -2738,43 +2738,43 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::Source - - + + Scanning (%L1 tracks) Scan en cours (%L1 titres) - + Scanning Scan en cours - + Checking Vérification - + Fetching Chargement - + Parsing Décodage - + Saving (%1%) Enregistrement (%1%) - + Online En Ligne - + Offline Hors ligne diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 85cdfaf0e..f86f9fde8 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form フォーム - + Scrobble tracks to Last.fm Last.fmにトラックをscrobbleする - + Username: ユーザー名: - + Password: パスワード: - + Test Login ログインを確認する - + Import Playback History @@ -1195,7 +1195,7 @@ other: %n週間 - + Latest Additions @@ -1215,42 +1215,42 @@ other: %n週間 スーパーコレクション - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1353,52 +1353,52 @@ other: %n週間 ステーション - + Browse - + Search History - + My Music マイミュージック - + SuperCollection スーパーコレクション - + Top Loved Tracks - + Dashboard ダッシュボード - + Recently Played 最近聴いたトラック - + Charts - + New Releases - + Friends @@ -1406,52 +1406,52 @@ other: %n週間 SpotifyConfig - + Form フォーム - + Configure your Spotify account - + Username or Facebook Email - + Log In ログイン - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1459,12 +1459,12 @@ other: %n週間 SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1604,8 +1604,8 @@ other: %n週間 - Remove Account - アカウントを削除 + Remove + @@ -1688,7 +1688,7 @@ other: %n週間 Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1696,49 +1696,49 @@ other: %n週間 Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1746,17 +1746,17 @@ other: %n週間 Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1764,22 +1764,22 @@ other: %n週間 Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... ログイン中... - + Logged in! ログインしました! - + Failed: %1 - + Log In ログイン @@ -1787,7 +1787,7 @@ other: %n週間 Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2586,27 +2586,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2726,7 +2726,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2734,43 +2734,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning 走査中 - + Checking - + Fetching 取得中 - + Parsing 解析中 - + Saving (%1%) - + Online - + Offline diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 9a49b147b..a36ae8004 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form - + Scrobble tracks to Last.fm Skrobluj utwory do Last.fm - + Username: Użytkownik: - + Password: Hasło: - + Test Login Test logowania - + Import Playback History @@ -1187,7 +1187,7 @@ connect and stream from you? - + Latest Additions Ostatnio Dodane @@ -1207,42 +1207,42 @@ connect and stream from you? Superkolekcja - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1345,52 +1345,52 @@ connect and stream from you? Stacja - + Browse Przeglądaj - + Search History Historia wyszukiwania - + My Music Moja Muzyka - + SuperCollection Superkolekcja - + Top Loved Tracks - + Dashboard - + Recently Played Ostatnio Odtworzone - + Charts Listy Przebojów - + New Releases Nowe Wydania - + Friends Znajomi @@ -1398,52 +1398,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: Użytkownik: - + Password: Hasło: @@ -1451,12 +1451,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1600,8 +1600,8 @@ indywidualnego profilu gustu. - Remove Account - Usuń Konto + Remove + @@ -1684,7 +1684,7 @@ indywidualnego profilu gustu. Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1692,49 +1692,49 @@ indywidualnego profilu gustu. Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1742,17 +1742,17 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1760,22 +1760,22 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1783,7 +1783,7 @@ indywidualnego profilu gustu. Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2584,27 +2584,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2724,7 +2724,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2732,43 +2732,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Skanowanie (%L1 utworów) - + Scanning Skanowanie - + Checking Sprawdzanie - + Fetching Pobieranie - + Parsing Analizowanie - + Saving (%1%) Zapisywanie (%1%) - + Online - + Offline diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 4b741a490..6ead6b8b4 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form - + Scrobble tracks to Last.fm - + Username: - + Password: Senha: - + Test Login - + Import Playback History @@ -1187,7 +1187,7 @@ connect and stream from you? - + Latest Additions @@ -1207,42 +1207,42 @@ connect and stream from you? - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1345,52 +1345,52 @@ connect and stream from you? Estação - + Browse Navegar - + Search History Histórico de Busca - + My Music - + SuperCollection - + Top Loved Tracks Faixas favoritas - + Dashboard Painel - + Recently Played - + Charts Gráficos - + New Releases - + Friends Amigos @@ -1398,52 +1398,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. Clique com o botão direito em qualquer playlist do Tomahawk para sincronizá-la com o Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: Senha: @@ -1451,12 +1451,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1599,8 +1599,8 @@ connect and stream from you? - Remove Account - Remover Conta + Remove + @@ -1683,7 +1683,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1691,49 +1691,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed Falhou - + Success Sucesso - + Could not contact server @@ -1741,17 +1741,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1759,22 +1759,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1782,7 +1782,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2583,27 +2583,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2723,7 +2723,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2731,43 +2731,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Escaneando (%L1 faixas) - + Scanning Escaneando - + Checking Verificando - + Fetching Buscando - + Parsing Analisando - + Saving (%1%) Guardando (%1%) - + Online - + Offline diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index c139bfcbe..d34c941b7 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -471,32 +471,32 @@ connect and stream from you? LastFmConfig - + Form Форма - + Scrobble tracks to Last.fm Скроблинг треков Last.fm - + Username: Имя пользователя: - + Password: Пароль: - + Test Login Проверить - + Import Playback History @@ -1189,7 +1189,7 @@ connect and stream from you? - + Latest Additions Последние добавленные @@ -1209,42 +1209,42 @@ connect and stream from you? Общая коллекция - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1347,52 +1347,52 @@ connect and stream from you? Станция - + Browse Просмотреть - + Search History История поиска - + My Music Моя музыка - + SuperCollection Общая коллекция - + Top Loved Tracks Топ любимых песен - + Dashboard Панель - + Recently Played Последние воспроизводимые - + Charts Чарты - + New Releases Новые релизы - + Friends Друзья @@ -1400,52 +1400,52 @@ connect and stream from you? SpotifyConfig - + Form Форма - + Configure your Spotify account Настроить аккаунт Spotify - + Username or Facebook Email Имя пользователя или Facebook Email - + Log In Войти - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams Поток высокого качества - + Spotify playlists to keep in sync: Синхронизировать плейлисты Spotify: - + Delete Tomahawk playlist when removing synchronization - + Username: Имя пользователя: - + Password: Пароль: @@ -1453,12 +1453,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? Удалить в Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1598,8 +1598,8 @@ connect and stream from you? - Remove Account - Удалить аккаунт + Remove + @@ -1682,7 +1682,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1690,49 +1690,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed Неудача - + Success Успех - + Could not contact server Не удается связаться с сервером @@ -1740,17 +1740,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify Синхронизировать с Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify Прекратить синхронизацию с Spotify @@ -1758,22 +1758,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... Вхожу... - + Logged in! Вход выполнен! - + Failed: %1 Ошибка: %1 - + Log In Войти @@ -1781,7 +1781,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2585,27 +2585,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2725,7 +2725,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2733,43 +2733,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Сканирование (%L1 песни) - + Scanning Сканирую - + Checking Проверяю - + Fetching Выбираю - + Parsing Анализирую - + Saving (%1%) Сохраняю (%1%) - + Online - + Offline diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 0d5e4907a..8cf31d97d 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form Formulär - + Scrobble tracks to Last.fm Scrobbla låtar till Last.fm - + Username: Användarnamn: - + Password: Lösenord: - + Test Login Testinloggning - + Import Playback History @@ -1188,7 +1188,7 @@ connect and stream from you? - + Latest Additions Senast tillagda @@ -1208,42 +1208,42 @@ connect and stream from you? SuperCollection - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1346,52 +1346,52 @@ connect and stream from you? Station - + Browse Bläddra - + Search History Sökhistorik - + My Music Min Musik - + SuperCollection SuperCollection - + Top Loved Tracks Mest älskade spår - + Dashboard - + Recently Played - + Charts - + New Releases - + Friends @@ -1399,52 +1399,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1452,12 +1452,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1597,7 +1597,7 @@ connect and stream from you? - Remove Account + Remove @@ -1681,7 +1681,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1689,49 +1689,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1739,17 +1739,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1757,22 +1757,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1780,7 +1780,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2579,27 +2579,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2719,7 +2719,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2727,43 +2727,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) Söker igenom (%L1 spår) - + Scanning - + Checking Kontrollerar - + Fetching Hämtar - + Parsing Tolkar - + Saving (%1%) Sparar (%1%) - + Online - + Offline diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 7c10de425..97c4c15f1 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form Form - + Scrobble tracks to Last.fm Dinlediğim şarkıların bilgisini Last.fm'e gönder. - + Username: Kullanıcı adı: - + Password: Parola: - + Test Login Bilgileri Test Et - + Import Playback History @@ -1187,7 +1187,7 @@ connect and stream from you? - + Latest Additions @@ -1207,42 +1207,42 @@ connect and stream from you? - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1345,52 +1345,52 @@ connect and stream from you? - + Browse - + Search History - + My Music - + SuperCollection - + Top Loved Tracks - + Dashboard - + Recently Played - + Charts - + New Releases - + Friends @@ -1398,52 +1398,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1451,12 +1451,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1596,7 +1596,7 @@ connect and stream from you? - Remove Account + Remove @@ -1680,7 +1680,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1688,49 +1688,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1738,17 +1738,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1756,22 +1756,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1779,7 +1779,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2578,27 +2578,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2718,7 +2718,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2726,43 +2726,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) - + Online - + Offline diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index ff0048d67..428ddea68 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form - + Scrobble tracks to Last.fm - + Username: 用户名 - + Password: 密码 - + Test Login 测试登录 - + Import Playback History @@ -1187,7 +1187,7 @@ connect and stream from you? - + Latest Additions @@ -1207,42 +1207,42 @@ connect and stream from you? - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1345,52 +1345,52 @@ connect and stream from you? - + Browse - + Search History - + My Music - + SuperCollection - + Top Loved Tracks - + Dashboard - + Recently Played - + Charts - + New Releases - + Friends @@ -1398,52 +1398,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email - + Log In - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization - + Username: - + Password: @@ -1451,12 +1451,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1596,7 +1596,7 @@ connect and stream from you? - Remove Account + Remove @@ -1680,7 +1680,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1688,49 +1688,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -1738,17 +1738,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1756,22 +1756,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... - + Logged in! - + Failed: %1 - + Log In @@ -1779,7 +1779,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2578,27 +2578,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2718,7 +2718,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2726,43 +2726,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) - + Online - + Offline diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 7cf9618c0..e366186f9 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -470,32 +470,32 @@ connect and stream from you? LastFmConfig - + Form - + Scrobble tracks to Last.fm - + Username: 用戶名稱: - + Password: 密碼: - + Test Login 測試登錄 - + Import Playback History @@ -1187,7 +1187,7 @@ connect and stream from you? - + Latest Additions 最新加入 @@ -1207,42 +1207,42 @@ connect and stream from you? 超級收藏 - + Sorry, we could not find any loved tracks! - + Latest additions to your collection - + Latest additions to %1's collection - + Sorry, we could not find any recent additions! - + Recently Played Tracks - + Your recently played tracks - + %1's recently played tracks - + Sorry, we could not find any recent plays! @@ -1345,52 +1345,52 @@ connect and stream from you? - + Browse 瀏覽 - + Search History 搜尋記錄 - + My Music 我的音樂 - + SuperCollection 超級收藏 - + Top Loved Tracks 最喜愛的曲目 - + Dashboard 儀表板 - + Recently Played 最近播放的 - + Charts - + New Releases 新版本 - + Friends 朋友 @@ -1398,52 +1398,52 @@ connect and stream from you? SpotifyConfig - + Form - + Configure your Spotify account - + Username or Facebook Email 使用者名稱或 Facebook 的電子郵件 - + Log In 登錄 - + Right click on any Tomahawk playlist to sync it to Spotify. - + High Quality Streams 高品質的串流 - + Spotify playlists to keep in sync: - + Delete Tomahawk playlist when removing synchronization 刪除同步時,刪除 Tomahawk 播放清單 - + Username: 用戶名稱: - + Password: 密碼: @@ -1451,12 +1451,12 @@ connect and stream from you? SpotifyPlaylistUpdater - + Delete in Spotify? - + Would you like to delete the corresponding Spotify playlist as well? @@ -1596,8 +1596,8 @@ connect and stream from you? - Remove Account - 刪除帳戶 + Remove + @@ -1680,7 +1680,7 @@ connect and stream from you? Tomahawk::Accounts::LastFmAccountFactory - + Scrobble your tracks to last.fm, and find freely downloadable tracks to play @@ -1688,49 +1688,49 @@ connect and stream from you? Tomahawk::Accounts::LastFmConfig - + Testing... - + Test Login - + Importing %1 e.g. Importing 2012/01/01 - + Importing History... - + History Incomplete. Resume - + Playback History Imported - - + + Failed 失敗 - + Success 成功 - + Could not contact server 無法聯繫服務器 @@ -1738,17 +1738,17 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccount - + Sync with Spotify - + Re-enable syncing with Spotify - + Stop syncing with Spotify @@ -1756,22 +1756,22 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountConfig - + Logging in... 登錄中... - + Logged in! 登錄了! - + Failed: %1 失敗:%1 - + Log In 登錄 @@ -1779,7 +1779,7 @@ connect and stream from you? Tomahawk::Accounts::SpotifyAccountFactory - + Play music from and sync your playlists with Spotify Premium @@ -2578,27 +2578,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::LastFmInfoPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists @@ -2718,7 +2718,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::ShortenedLinkParser - + Network error parsing shortened link! @@ -2726,43 +2726,43 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing 解析 - + Saving (%1%) - + Online - + Offline From 37d1c88b425b821d622680a70197cb688ddcf226 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sat, 9 Jun 2012 22:16:47 +0000 Subject: [PATCH 342/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 55303b1cf..2b5a61eef 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -1602,7 +1602,7 @@ connect and stream from you? Remove - + إزالة From 99d84c6489b522c5cea807013812cb13d045c5cf Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 10 Jun 2012 09:08:01 +0200 Subject: [PATCH 343/433] Only install from attica when checking, even if we have checked + uninstalled --- src/libtomahawk/accounts/AccountModel.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 2f263b9ac..7b03cbe7d 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -416,6 +416,9 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( role == CheckboxClickedRole ) { Account* acct = 0; + + Qt::CheckState checkState = static_cast< Qt::CheckState >( value.toInt() ); + switch ( node->type ) { case AccountModelNode::UniqueFactoryType: @@ -453,9 +456,11 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role state = AtticaManager::Uninstalled; } - if ( state == AtticaManager::Installed ) + // Don't install if we're unchecking. This happens if e.g. the user deletes his config file + // and opens tomahawk + if ( state == AtticaManager::Installed || checkState == Qt::Unchecked ) { - qDebug() << "Already installed with resolver, just enabling"; + qDebug() << "Already installed with resolver, or unchecking, just enabling/disabling"; acct = node->atticaAccount; break; } @@ -491,13 +496,10 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( node->type == AccountModelNode::FactoryType ) { - // Turn on or off all accounts for this factory - - Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() ); - + // Turn on or off all accounts for this factory\ foreach ( Account* acct, node->accounts ) { - state == Qt::Checked ? AccountManager::instance()->enableAccount( acct ) + checkState == Qt::Checked ? AccountManager::instance()->enableAccount( acct ) : AccountManager::instance()->disableAccount( acct ); } From 4bc703b47719ad7219743b3a29560943c882ebe9 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 10 Jun 2012 17:29:56 +0200 Subject: [PATCH 344/433] Make grey text visible when highlighted in playlist delegate --- src/libtomahawk/playlist/PlaylistItemDelegate.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/PlaylistItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistItemDelegate.cpp index 494b683f7..72655c61f 100644 --- a/src/libtomahawk/playlist/PlaylistItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistItemDelegate.cpp @@ -201,7 +201,11 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_topOption ); painter->setFont( opt.font ); - painter->setPen( Qt::gray ); + if ( option.state & QStyle::State_Selected ) + painter->setPen( option.palette.color( QPalette::HighlightedText ) ); + else + painter->setPen( Qt::gray ); + text = painter->fontMetrics().elidedText( lowerText, Qt::ElideRight, r.width() ); painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_bottomOption ); } From 60f8241305bd4c6cc90b9100b8832245dc0bf6fd Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 10 Jun 2012 17:35:51 +0200 Subject: [PATCH 345/433] Draw small text with highlighted color in large delegate if selected --- src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp | 10 +++++++--- src/libtomahawk/playlist/PlaylistLargeItemDelegate.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp index 1ca6b793f..6783a0d3e 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -99,7 +99,7 @@ PlaylistLargeItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, c void -PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QRect& rect, int flags, QTextDocument& text ) const +PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, int flags, QTextDocument& text ) const { text.setPageSize( QSize( rect.width(), QWIDGETSIZE_MAX ) ); QAbstractTextDocumentLayout* layout = text.documentLayout(); @@ -112,7 +112,11 @@ PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QRect& rect, i y += ( rect.height() - height ) / 2; QAbstractTextDocumentLayout::PaintContext context; - context.palette.setColor( QPalette::Text, painter->pen().color() ); + + if ( option.state & QStyle::State_Selected ) + context.palette.setColor( QPalette::Text, option.palette.color( QPalette::HighlightedText ) ); + else + context.palette.setColor( QPalette::Text, painter->pen().color() ); painter->save(); painter->translate( rect.x(), y ); @@ -235,7 +239,7 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& if ( textDoc.idealWidth() > leftRect.width() ) textDoc.setHtml( item->query()->socialActionDescription( "Love", Query::Short ) ); - drawRichText( painter, leftRect, Qt::AlignBottom, textDoc ); + drawRichText( painter, option, leftRect, Qt::AlignBottom, textDoc ); if ( duration > 0 ) { diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h index d6b33f076..9fed77936 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h @@ -59,7 +59,7 @@ private slots: private: void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const; - void drawRichText( QPainter* painter, const QRect& rect, int flags, QTextDocument& text ) const; + void drawRichText( QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, int flags, QTextDocument& text ) const; QTextOption m_topOption; QTextOption m_centerRightOption; From c114657f811038d901325d71784b44ab134a001f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 10 Jun 2012 17:56:26 +0200 Subject: [PATCH 346/433] TWK-911: Fix placement of social widget --- src/AudioControls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 58e6fba06..a286bf9c5 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -598,7 +598,7 @@ void AudioControls::onSocialButtonClicked() { SocialWidget* sw = new SocialWidget( m_parent ); - sw->setPosition( QCursor::pos() ); + sw->setPosition( sw->mapFromGlobal( QCursor::pos() ) ); sw->setQuery( m_currentTrack->toQuery() ); sw->show(); } From 9218488409d5f4fe7e633842e38f4e2d1602deb1 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 10 Jun 2012 22:02:19 +0200 Subject: [PATCH 347/433] TWK-879: Ensure bredcrumb arrow is the right proportions --- src/libtomahawk/widgets/BreadcrumbButton.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/BreadcrumbButton.cpp b/src/libtomahawk/widgets/BreadcrumbButton.cpp index 3f1aa2809..f4f385123 100644 --- a/src/libtomahawk/widgets/BreadcrumbButton.cpp +++ b/src/libtomahawk/widgets/BreadcrumbButton.cpp @@ -34,7 +34,11 @@ using namespace Tomahawk; class BreadcrumbArrow : public QWidget { public: - BreadcrumbArrow(QWidget* parent) : QWidget(parent) {} + BreadcrumbArrow( QWidget* parent ) + : QWidget(parent) + { + setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + } protected: virtual void paintEvent( QPaintEvent* ) { From 5a534954cca47d07568c3e5078f6692ce742fe9c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 10 Jun 2012 22:53:29 +0200 Subject: [PATCH 348/433] Explicitly set working dir of script resolvers being launched --- src/libtomahawk/resolvers/ScriptResolver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 3b7c58276..bde843ab3 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -442,7 +442,11 @@ void ScriptResolver::startProcess() #endif // Q_OS_WIN if( interpreter.isEmpty() ) + { + const QFileInfo info( runPath ); + m_proc.setWorkingDirectory( info.absolutePath() ); m_proc.start( runPath ); + } else m_proc.start( interpreter, QStringList() << filePath() ); From 36bbeb9d5a4cfd12cfcb15449613de2d3613e203 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sun, 10 Jun 2012 22:16:56 +0000 Subject: [PATCH 349/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 10 +- lang/tomahawk_bg.ts | 10 +- lang/tomahawk_ca.ts | 10 +- lang/tomahawk_de.ts | 10 +- lang/tomahawk_en.ts | 10 +- lang/tomahawk_es.ts | 10 +- lang/tomahawk_fr.ts | 10 +- lang/tomahawk_ja.ts | 387 +++++++++++++++++++++-------------------- lang/tomahawk_pl.ts | 10 +- lang/tomahawk_pt_BR.ts | 10 +- lang/tomahawk_ru.ts | 10 +- lang/tomahawk_sv.ts | 10 +- lang/tomahawk_tr.ts | 10 +- lang/tomahawk_zh_CN.ts | 10 +- lang/tomahawk_zh_TW.ts | 10 +- 15 files changed, 265 insertions(+), 262 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 2b5a61eef..ca51f99ba 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -692,17 +692,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you سمعت %1 - + played %1 by %2 %2 سمع %1 - + added %1 إضافة %1 @@ -1628,12 +1628,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required مطلوب تثبيت يدوي - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على منصتك. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index d1b271e5e..e98480f43 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -694,17 +694,17 @@ Tomahaw създаде доклад относно това и изпращай PlaylistLargeItemDelegate - + played %1 by you изпълнена %1 от мен - + played %1 by %2 изпълнена %1 от %2 - + added %1 добавен %1 @@ -1631,12 +1631,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountModel - + Manual Install Required Изисква се ръчно инсталиране - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 За съжаление, автоматичното инсталиране на този компонен е деактивирано за твоята платформа. <br /><br /> diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 5174091cf..a22796f72 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you reproduït %1 - + played %1 by %2 reproduït %1 per %2 - + added %1 afegit %1 @@ -1627,12 +1627,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 3aec518c7..4fadc0e53 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you angehört %1 von dir - + played %1 by %2 hörte %1 von %2 - + added %1 fügte %1 hinzu @@ -1624,12 +1624,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manuelle Installation benötigt - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 5c75699c1..0e1899083 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -692,17 +692,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you played %1 by you - + played %1 by %2 played %1 by %2 - + added %1 added %1 @@ -1628,12 +1628,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 14b77a46d..71e1dc0d7 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you %1 reproducido por usted - + played %1 by %2 %1 reproducido por %2 - + added %1 añadio %1 @@ -1626,12 +1626,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 28639893e..dbb14fbdf 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -692,17 +692,17 @@ se connecter et streamer depuis chez vous ? PlaylistLargeItemDelegate - + played %1 by you joué %1 par vous - + played %1 by %2 joué %1 par %2 - + added %1 ajouté par %1 @@ -1628,12 +1628,12 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::AccountModel - + Manual Install Required Installation manuelle requise - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Malheureusement, l'installation automatique de ce script de résolution n'est pas disponible ou a été désactivé sur votre plateforme.<br /><br />Utiliser "Installer depuis un fichier" ci-dessus et téléchargez le fichier pour votre distribution, ou compilez-le. D'autres instructions sont disponibles ici :<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index f86f9fde8..d9c300296 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -40,14 +40,14 @@ Error displaying ACL info - + エラーが発生したため、ACLの情報を表示できません Allow %1 to connect and stream from you? - + %1と接続して、音楽配信を許可しますか? @@ -187,7 +187,7 @@ connect and stream from you? Sorry, we could not find any albums for this artist! - + このアーティストのアルバムは見つかりませんでした。 @@ -240,7 +240,7 @@ connect and stream from you? social - + ソーシャル @@ -283,12 +283,12 @@ connect and stream from you? Create new Playlist - + 新規プレイリストを作成 Create new Station - + 新規ステーションを作成 @@ -331,7 +331,7 @@ connect and stream from you? InfoBar - + インフォメーションバー @@ -355,27 +355,28 @@ connect and stream from you? <html><head/><body><p><span style=" font-weight:600;">Sorry!</span> Tomahawk crashed. Please tell us about it! Tomahawk has created an error report for you that can help improve the stability in the future. You can now send this report directly to the Tomahawk developers.</p></body></html> - + <html><head/><body><p>Tomahawkがクラッシュしました。その情報をTomahawkに送信してください。安定した機能に改善するためにエラーレポートを用意しています。このレポートはTomahawkの開発者に直接送られます。</p></body></html> Send this report - + レポートを送信 Don't send - + 送信しない Abort - アボート + 中止する You can disable sending crash reports in the configuration dialog. - + 設定ダイアログでクラッシュレポートの送信を無効にすることができます。 + @@ -422,7 +423,7 @@ connect and stream from you? About this Account - + このアカウントについて @@ -459,7 +460,7 @@ connect and stream from you? InfoBar - + インフォメーションバー @@ -497,7 +498,7 @@ connect and stream from you? Import Playback History - + 再生履歴をインポートする @@ -603,7 +604,7 @@ connect and stream from you? New Releases - + ニューリリース @@ -616,12 +617,12 @@ connect and stream from you? Title - + タイトル Composer - + 作曲者 @@ -631,48 +632,48 @@ connect and stream from you? Track - + トラック Duration - + 時間 Bitrate - + ビットレート Age - + 変更日 Year - + Size - + サイズ Origin - + 音源 Score - + スコア Name - + 名前 @@ -691,17 +692,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you %1を再生しました。 - + played %1 by %2 %2が%1を再生しました。 - + added %1 %1を追加しました。 @@ -749,7 +750,7 @@ connect and stream from you? Name: - + 名前: @@ -772,7 +773,7 @@ connect and stream from you? This playlist is currently empty. - + このプレイリストには何も入っていません。 @@ -845,59 +846,52 @@ connect and stream from you? %n year(s) ago - one: %n年前 - -other: %n年前 + %n年前 %n year(s) - one: %n年 -other: %n年 + %n年 %n month(s) ago - one: %nヶ月前 -other: %nヶ月前 + %nヶ月前 %n month(s) - one: %nヶ月 -other: %nヶ月 + %nヶ月 %n week(s) ago - one: %n週間前 -other: %n週間前 + %n週間前 %n week(s) - one: %n週間 -other: %n週間 + %n週間 %n day(s) ago - + %n日前 %n day(s) - + %n日 %n hour(s) ago - + %n時間前 %n hour(s) - + %n時間 @@ -912,22 +906,22 @@ other: %n週間 just now - 只今 + たった今 Friend Finders - + 友達を探す Music Finders - + 音楽を探す Status Updaters - + ステータスを更新 @@ -935,7 +929,7 @@ other: %n週間 ZIP/UNZIP API error %1 - + ZIP/UNZIP API error %1 @@ -943,28 +937,28 @@ other: %n週間 InfoBar - + インフォメーションバー Open Queue - + キューを表示 The queue is currently empty. Drop something to enqueue it! - + キュの中には何も入っていません。何かキューにドロップしましょう! Open Queue - %n item(s) - + キューを表示 - %n項目 Close Queue - + キューを隠す @@ -972,7 +966,7 @@ other: %n週間 Related Artists - + 似たアーティスト @@ -980,12 +974,12 @@ other: %n週間 Not found: %1 - + 見つかりません: %1 Failed to load: %1 - + ロードに失敗しました: %1 @@ -1001,12 +995,12 @@ other: %n週間 Search: %1 - + 検索: %1 Results for '%1' - + '%1'の結果 @@ -1014,32 +1008,32 @@ other: %n週間 Collection - + コレクション Advanced - + 詳細 All - + すべて Some changed settings will not take effect until Tomahawk is restarted - + Tomahawkを再起動すると設定変更が反映されます Services - + サービス Install resolver from file - + ファイルからリゾルバをインストールする @@ -1057,7 +1051,7 @@ other: %n週間 Most Played Playlists - + 最も再生しているプレイリスト @@ -1631,12 +1625,12 @@ other: %n週間 Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1807,20 +1801,20 @@ other: %n週間 Tweet! - + ツイート! Status: No saved credentials - + ステータス: 保存された認証情報がありません Authenticate - + 認証 @@ -1869,17 +1863,17 @@ You may wish to try re-authenticating. Send Message! - メッセージを送信! + メッセージを送信! @Mention - + @メンション Send Mention! - + メンションを送信! @@ -2877,7 +2871,7 @@ enter the displayed PIN number here: &Controls - + &制御 @@ -2967,7 +2961,7 @@ enter the displayed PIN number here: Minimize - 最小か + 最小化 @@ -2982,7 +2976,8 @@ enter the displayed PIN number here: Meta+Ctrl+Z - + +Meta+Ctrl+Z @@ -3013,12 +3008,12 @@ enter the displayed PIN number here: Previous - + 前へ Next - + 次へ @@ -3106,7 +3101,7 @@ enter the displayed PIN number here: Station - + ステーション @@ -3131,7 +3126,7 @@ enter the displayed PIN number here: Pause - + 一時停止 @@ -3157,38 +3152,38 @@ enter the displayed PIN number here: %1 by %2 track, artist name - + %1 by %2 %1 - %2 current track, some window title - + %1 - %2 <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1</h2> - + <h2><b>Tomahawk %1</h2> Copyright 2010 - 2012 - + Copyright 2010 - 2012 Thanks to: - + Thanks to: About Tomahawk - + Tomahawkについて @@ -3201,22 +3196,22 @@ enter the displayed PIN number here: 0 Sources - + ソースがありません。 0 Tracks - + トラックがありません 0 Artists - + アーティストがいません。 0 Shown - + 何もありません。 @@ -3236,22 +3231,22 @@ enter the displayed PIN number here: Artist View - + アーティストビュー Flat View - + フラットビュー Sources - + ソース Shown - + 項目 @@ -3259,7 +3254,7 @@ enter the displayed PIN number here: Top Hits - + TOP HITS @@ -3267,32 +3262,32 @@ enter the displayed PIN number here: Form - + フォーム Cover - + カバー Track - + トラック by - + by Artist - + アーティスト from - + from @@ -3302,7 +3297,7 @@ enter the displayed PIN number here: Statistics - + 統計 @@ -3312,37 +3307,37 @@ enter the displayed PIN number here: Similar Tracks - + 似ているトラック Sorry, but we could not find similar tracks for this song! - + この曲に似ているトラックが見つかりませんでした。 You've listened to this track %n time(s). - + このトラックは%n回聴いています。 You've never listened to this track before. - + このトラックを一度も聴いていません。 You first listened to it on %1. - + 初めてこの曲を聴いたのは、%1です。 You've listened to %1 %n time(s). - + %1を%n回聴いています。 You've never listened to %1 before. - + %1を一度も聴いていません。 @@ -3358,12 +3353,12 @@ enter the displayed PIN number here: from - + から to - + まで @@ -3371,7 +3366,7 @@ enter the displayed PIN number here: Unknown - + 不明 @@ -3385,13 +3380,13 @@ enter the displayed PIN number here: My Collection - + マイコレクション Collection of %1 - + %1のコレクション @@ -3399,7 +3394,7 @@ enter the displayed PIN number here: Sorry, your filter '%1' did not match any results. - + %1に一致する結果は見つかりませんでした。 @@ -3407,27 +3402,27 @@ enter the displayed PIN number here: Configure this Twitter account - + このTwitterアカウントを設定する The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - + TwitterプラグインはTomahawkを使っているTwitterの友達があなたの曲を見つけて再生したり、あなたにメッセージを投稿することを許可します。 Status: No saved credentials - + ステータス: 保存された認証情報がありません Authenticate with Twitter - + Twitterで認証する Twitter Connections - + Twitter接続 @@ -3437,37 +3432,42 @@ If you only want to post tweets, you're done. If you want to connect Tomahawk to your friends using Twitter, select the type of tweet and press the button below to send a sync message. You must both be following each other as Direct Messages are used. Then be (very) patient -- it can take several minutes! You can re-send a sync message at any time simply by sending another tweet using the button. - + +ツイートするだけなら、これで設定は完了です。 + +Twitterを使っている友達にTomahawkを接続したいなら、ツイートの種類を選択し、以下のボタンを押してメッセージを送信して下さい。ダイレクトメッセージを使用するためにお互いのフォローが必要です。時間がかかる場合がありますので、しばらくお待ち下さい。 + +ボタンを押してもう一度ツイートを送信すると、メッセージをいつでも再送信できます。 Select the kind of tweet you would like, then press the button to post it: - + ツイートの種類を選択し、ボタンを押して投稿してください: Global Tweet - + ツイートする @Mention - + @メンション Direct Message - + ダイレクトメッセージ e.g. @tomahawk - + (例) @tomahawk Send Message - + メッセージを送信 @@ -3475,37 +3475,38 @@ You can re-send a sync message at any time simply by sending another tweet using After you have scanned your music collection you will find your tracks right here. - + コレクションのスキャンが完了したら、トラックはここに表示されます。 This collection is empty. - + このコレクションには何も入っていません。 SuperCollection - + スーパーコレクション Combined libraries of all your online friends - + オンラインの友達全員のライブラリ All available albums - + すべてのアルバム + Recently Played Tracks - + 最近再生したトラック Recently played tracks from all your friends - + 友達の最近再生したトラック @@ -3513,27 +3514,27 @@ You can re-send a sync message at any time simply by sending another tweet using Recent Additions - + 最近追加した項目 Newest Stations & Playlists - + 最新のステーション & プレイリスト Recently Played Tracks - + 最近再生したトラック No recently created playlists in your network. - + ネットワークに最近作成したプレイリストはありません。 Welcome to Tomahawk - + Tomahawkへようこそ @@ -3541,7 +3542,7 @@ You can re-send a sync message at any time simply by sending another tweet using Charts - + チャート @@ -3549,7 +3550,7 @@ You can re-send a sync message at any time simply by sending another tweet using Wikipedia - + ウィキペディア @@ -3559,12 +3560,14 @@ You can re-send a sync message at any time simply by sending another tweet using Terms for %1: - + +%1の語句: + No terms found, sorry. - + 語句と一致する結果は見つかりませんでした。 @@ -3610,7 +3613,7 @@ Lyrics for "%1" by %2: New Playlist - + 新規プレイリスト @@ -3624,32 +3627,32 @@ Lyrics for "%1" by %2: Filter - + フィルター Save log - + ログを保存 Disabled - + 無効 By JID - + JIDの順に分類する By namespace uri - + ネームスペースのURIの順に分類する By all attributes - + すべての属性の順に分類する @@ -3664,32 +3667,32 @@ Lyrics for "%1" by %2: Message - + メッセージ Presence - + 状態 Custom - + カスタム Close - + 閉じる Save XMPP log to file - + XMPPのログをファイルに保存する OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) - + OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) @@ -3697,32 +3700,32 @@ Lyrics for "%1" by %2: Xmpp Configuration - + XMPP設定 Configure this Xmpp account - + XMPPアカウントを設定 Enter your Xmpp login to connect with your friends using Tomahawk! - + Tomahawkを使っている友達とつながるためにXMPPログインを入力してください。 Login Information - + ログイン情報 Xmpp ID: - + XMPP ID: e.g. user@example.com - + (例) user@example.com @@ -3732,12 +3735,12 @@ Lyrics for "%1" by %2: An account with this name already exists! - + この名前のアカウントは既に存在しています! Advanced Xmpp Settings - + XMPPの詳細設定 @@ -3752,17 +3755,17 @@ Lyrics for "%1" by %2: Lots of servers don't support this (e.g. GTalk, jabber.org) - + 多くのサーバで対応していません(例: GTalk, jabber.org) Publish currently playing track - + 今現在再生しているトラックを公開する Enforce secure connection - + 安全な接続を強制する @@ -3770,92 +3773,92 @@ Lyrics for "%1" by %2: User Interaction - + ユーザインタラクション Host is unknown - + 不明なホスト Item not found - + 項目が見つかりません Authorization Error - + 認証エラー Remote Stream Error - + 配信エラー Remote Connection failed - + 接続に失敗しました Internal Server Error - + サーバ内部エラー System shutdown - + システム終了 Conflict - + コンフリクト Unknown - + 不明 No Compression Support - + 圧縮に対応していません No Encryption Support - + 暗号化に対応していません No Authorization Support - + Authorizationに対応していません No Supported Feature - + 未対応昨機能 Add Friend - + 友達を追加 Enter Xmpp ID: - + XMPP IDを入力: Add Friend... - + 友達を追加... XML Console... - + XMLコンソール... diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index a36ae8004..970beaa82 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you odtworzone %1 przez ciebie - + played %1 by %2 - + added %1 dodano %1 @@ -1627,12 +1627,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 6ead6b8b4..ea03d2230 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you tocada %1 por você - + played %1 by %2 tocada %1 por %2 - + added %1 adicionou %1 @@ -1626,12 +1626,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index d34c941b7..2a6ae3d9c 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -692,17 +692,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you Воспроизводилось %1 вами - + played %1 by %2 Воспроизводилось %1 %2 - + added %1 Добавлено %1 @@ -1625,12 +1625,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 8cf31d97d..5944d6c16 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you %1 spelades av dig - + played %1 by %2 %1 spelades av %2 - + added %1 %1 tillagd @@ -1624,12 +1624,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 97c4c15f1..fab909847 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you - + played %1 by %2 - + added %1 @@ -1623,12 +1623,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 428ddea68..fa2f64bb5 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you - + played %1 by %2 - + added %1 @@ -1623,12 +1623,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index e366186f9..bfe2f4f67 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -691,17 +691,17 @@ connect and stream from you? PlaylistLargeItemDelegate - + played %1 by you - + played %1 by %2 - + added %1 @@ -1623,12 +1623,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 From 26729f6f870b3ab1ae260e1a7e69a2264c178240 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 11 Jun 2012 11:03:15 +0200 Subject: [PATCH 350/433] Extra safety, but wtf --- src/libtomahawk/accounts/AccountModel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 7b03cbe7d..41a1963c1 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -496,9 +496,14 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role if ( node->type == AccountModelNode::FactoryType ) { - // Turn on or off all accounts for this factory\ + tLog() << "Factory account with members:" << node->accounts << node->accounts.size(); + // Turn on or off all accounts for this factory foreach ( Account* acct, node->accounts ) { + tLog() << "Account we are toggling for factory:" << acct; + if ( !acct ) + continue; + checkState == Qt::Checked ? AccountManager::instance()->enableAccount( acct ) : AccountManager::instance()->disableAccount( acct ); } From 31f4c4f656b1e9c5b5f468b2379793d9c2749d4f Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Mon, 11 Jun 2012 20:37:49 +0200 Subject: [PATCH 351/433] liblastfm pulls in ${QT_LIBRARIES} as dep for libtomahawk, mention all needed components explicitly as well --- src/libtomahawk/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index d3b4c8ed3..cd58acc37 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -433,7 +433,11 @@ TARGET_LINK_LIBRARIES( tomahawklib ${QT_QTSQL_LIBRARY} ${QT_QTUITOOLS_LIBRARY} ${QT_QTGUI_LIBRARY} + ${QT_QTWEBKIT_LIBRARY} ${QT_QTSCRIPT_LIBRARY} + ${QT_QTNETWORK_LIBRARY} + ${QT_QTXML_LIBRARY} + ${QT_QTCORE_LIBRARY} ${OS_SPECIFIC_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${LINK_LIBRARIES} From 22bca7ed12658735acc1483c56b7688697c023b3 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Mon, 11 Jun 2012 22:04:50 +0200 Subject: [PATCH 352/433] Update FindLibLastFm for liblastfm-1.0.0 --- CMakeModules/FindLibLastFm.cmake | 59 ++++++++++++++------------------ 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/CMakeModules/FindLibLastFm.cmake b/CMakeModules/FindLibLastFm.cmake index c73038a7d..76994ec24 100644 --- a/CMakeModules/FindLibLastFm.cmake +++ b/CMakeModules/FindLibLastFm.cmake @@ -1,42 +1,33 @@ -# - Find LibLastFM -# Find the liblastfm includes and the liblastfm libraries -# This module defines -# LIBLASTFM_INCLUDE_DIR, root lastfm include dir -# LIBLASTFM_LIBRARY, the path to liblastfm -# LIBLASTFM_FOUND, whether liblastfm was found +# - Try to find LibLastFm +# +# LIBLASTFM_FOUND - system has QTweetLib +# LIBLASTFM_INCLUDE_DIRS - the QTweetLib include directories +# LIBLASTFM_LIBRARIES - link these to use QTweetLib +# +# (c) Dominik Schmidt +# +# Dependencies +if(NOT QT4_FOUND) + find_package(Qt4 REQUIRED) +endif() -find_path(LIBLASTFM_INCLUDE_DIR NAMES Audioscrobbler - HINTS - ~/usr/include - /opt/local/include - /usr/local/include - /usr/include - /opt/kde4/include - ${KDE4_INCLUDE_DIR} - PATH_SUFFIXES lastfm +# Include dir +find_path(LIBLASTFM_INCLUDE_DIR + NAMES lastfm/global.h + PATHS ${KDE4_INCLUDE_DIR} ) -find_library( LIBLASTFM_LIBRARY NAMES lastfm - PATHS - ~/usr/lib - /opt/local/lib - /usr/local/lib - /usr/lib - /usr/lib64 - /opt/kde4/lib - ${KDE4_LIB_DIR} +# Finally the library itself +find_library(LIBLASTFM_LIBRARY + NAMES lastfm + PATHS ${KDE4_LIB_DIR} ) +set(LIBLASTFM_LIBRARIES ${LIBLASTFM_LIBRARY}) +set(LIBLASTFM_INCLUDE_DIRS ${LIBLASTFM_LIBRARY}) -if(LIBLASTFM_INCLUDE_DIR AND LIBLASTFM_LIBRARY) - set(LIBLASTFM_FOUND TRUE) - message(STATUS "Found liblastfm: ${LIBLASTFM_INCLUDE_DIR}, ${LIBLASTFM_LIBRARY}") -else(LIBLASTFM_INCLUDE_DIR AND LIBLASTFM_LIBRARY) - set(LIBLASTFM_FOUND FALSE) - if (LIBLASTFM_FIND_REQUIRED) - message(FATAL_ERROR "Could NOT find required package LibLastFm") - endif(LIBLASTFM_FIND_REQUIRED) -endif(LIBLASTFM_INCLUDE_DIR AND LIBLASTFM_LIBRARY) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibLastFm DEFAULT_MSG LIBLASTFM_LIBRARIES LIBLASTFM_INCLUDE_DIRS) -mark_as_advanced(LIBLASTFM_INCLUDE_DIR LIBLASTFM_LIBRARY) +mark_as_advanced(LIBLASTFM_LIBRARIES LIBLASTFM_INCLUDE_DIRS) From 6f9a79404db7f7ae3620788606647558731f6805 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Mon, 11 Jun 2012 22:08:35 +0200 Subject: [PATCH 353/433] Really only find liblastfm-1.0.0 include dirs --- CMakeModules/FindLibLastFm.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeModules/FindLibLastFm.cmake b/CMakeModules/FindLibLastFm.cmake index 76994ec24..e7cd40134 100644 --- a/CMakeModules/FindLibLastFm.cmake +++ b/CMakeModules/FindLibLastFm.cmake @@ -14,7 +14,8 @@ endif() # Include dir find_path(LIBLASTFM_INCLUDE_DIR - NAMES lastfm/global.h + # Track.h doesn't exist in liblastfm-0.3.1, was called Track back then + NAMES lastfm/Track.h PATHS ${KDE4_INCLUDE_DIR} ) From d77c9eb3eb891cdc78fac499502bb22e64e2bb11 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 11 Jun 2012 21:10:08 +0200 Subject: [PATCH 354/433] * Removed liblastfm2 from thirdparty/. --- thirdparty/liblastfm2/CMakeLists.txt | 27 - thirdparty/liblastfm2/COPYING | 621 ------------ thirdparty/liblastfm2/README.md | 126 --- .../cmake/modules/FindLibFFTW3.cmake | 45 - .../cmake/modules/FindLibSamplerate.cmake | 22 - thirdparty/liblastfm2/demos/demo1.cpp | 95 -- thirdparty/liblastfm2/demos/demo2.cpp | 114 --- thirdparty/liblastfm2/demos/demo3.cpp | 63 -- thirdparty/liblastfm2/demos/demos.pro | 3 - thirdparty/liblastfm2/lastfm.pro | 142 --- thirdparty/liblastfm2/src/CMakeLists.txt | 125 --- thirdparty/liblastfm2/src/core/README | 8 - thirdparty/liblastfm2/src/core/UrlBuilder.cpp | 83 -- thirdparty/liblastfm2/src/core/UrlBuilder.h | 69 -- thirdparty/liblastfm2/src/core/XmlQuery.cpp | 105 -- thirdparty/liblastfm2/src/core/XmlQuery.h | 78 -- thirdparty/liblastfm2/src/core/misc.cpp | 175 ---- thirdparty/liblastfm2/src/core/misc.h | 111 -- .../liblastfm2/src/fingerprint/CMakeLists.txt | 32 - .../liblastfm2/src/fingerprint/Collection.cpp | 267 ----- .../liblastfm2/src/fingerprint/Collection.h | 59 -- .../liblastfm2/src/fingerprint/EXAMPLE.cpp | 76 -- .../src/fingerprint/Fingerprint.cpp | 300 ------ .../liblastfm2/src/fingerprint/Fingerprint.h | 116 --- .../src/fingerprint/FingerprintableSource.h | 48 - .../liblastfm2/src/fingerprint/Sha256.cpp | 480 --------- .../liblastfm2/src/fingerprint/Sha256.h | 180 ---- .../src/fingerprint/contrib/AacSource.cpp | 953 ------------------ .../src/fingerprint/contrib/AacSource.h | 46 - .../src/fingerprint/contrib/AacSource_p.h | 94 -- .../src/fingerprint/contrib/FlacSource.cpp | 339 ------- .../src/fingerprint/contrib/FlacSource.h | 74 -- .../src/fingerprint/contrib/MadSource.cpp | 514 ---------- .../src/fingerprint/contrib/MadSource.h | 69 -- .../src/fingerprint/contrib/VorbisSource.cpp | 204 ---- .../src/fingerprint/contrib/VorbisSource.h | 47 - .../contrib/lastfm-fingerprint.pro | 13 - .../src/fingerprint/contrib/main.cpp | 173 ---- .../src/fingerprint/fingerprint.pro | 25 - .../src/fingerprint/fplib/CircularArray.h | 292 ------ .../src/fingerprint/fplib/Filter.cpp | 128 --- .../liblastfm2/src/fingerprint/fplib/Filter.h | 47 - .../fplib/FingerprintExtractor.cpp | 786 --------------- .../fingerprint/fplib/FingerprintExtractor.h | 77 -- .../src/fingerprint/fplib/FloatingAverage.h | 106 -- .../src/fingerprint/fplib/OptFFT.cpp | 411 -------- .../liblastfm2/src/fingerprint/fplib/OptFFT.h | 63 -- .../src/fingerprint/fplib/fp_helper_fun.h | 443 -------- thirdparty/liblastfm2/src/global.h | 132 --- thirdparty/liblastfm2/src/lastfm.pro | 87 -- .../liblastfm2/src/radio/RadioStation.cpp | 337 ------- .../liblastfm2/src/radio/RadioStation.h | 123 --- .../liblastfm2/src/radio/RadioTuner.cpp | 219 ---- thirdparty/liblastfm2/src/radio/RadioTuner.h | 85 -- .../src/scrobble/Audioscrobbler.cpp | 246 ----- .../liblastfm2/src/scrobble/Audioscrobbler.h | 78 -- .../liblastfm2/src/scrobble/ScrobbleCache.cpp | 163 --- .../liblastfm2/src/scrobble/ScrobbleCache.h | 84 -- .../liblastfm2/src/scrobble/ScrobblePoint.h | 59 -- .../liblastfm2/src/types/AbstractType.h | 43 - thirdparty/liblastfm2/src/types/Album.cpp | 87 -- thirdparty/liblastfm2/src/types/Album.h | 73 -- thirdparty/liblastfm2/src/types/Artist.cpp | 230 ----- thirdparty/liblastfm2/src/types/Artist.h | 105 -- .../liblastfm2/src/types/FingerprintId.cpp | 55 - .../liblastfm2/src/types/FingerprintId.h | 62 -- thirdparty/liblastfm2/src/types/Mbid.cpp | 36 - thirdparty/liblastfm2/src/types/Mbid.h | 45 - thirdparty/liblastfm2/src/types/Playlist.cpp | 63 -- thirdparty/liblastfm2/src/types/Playlist.h | 51 - thirdparty/liblastfm2/src/types/Tag.cpp | 77 -- thirdparty/liblastfm2/src/types/Tag.h | 63 -- .../liblastfm2/src/types/Tasteometer.cpp | 20 - thirdparty/liblastfm2/src/types/Tasteometer.h | 18 - thirdparty/liblastfm2/src/types/Track.cpp | 653 ------------ thirdparty/liblastfm2/src/types/Track.h | 367 ------- thirdparty/liblastfm2/src/types/User.cpp | 317 ------ thirdparty/liblastfm2/src/types/User.h | 184 ---- thirdparty/liblastfm2/src/types/Xspf.cpp | 75 -- thirdparty/liblastfm2/src/types/Xspf.h | 52 - thirdparty/liblastfm2/src/types/mbid_mp3.c | 181 ---- .../src/ws/InternetConnectionMonitor.cpp | 117 --- .../src/ws/InternetConnectionMonitor.h | 80 -- .../src/ws/NetworkAccessManager.cpp | 159 --- .../liblastfm2/src/ws/NetworkAccessManager.h | 66 -- .../src/ws/NetworkConnectionMonitor.cpp | 51 - .../src/ws/NetworkConnectionMonitor.h | 46 - .../src/ws/linux/LNetworkConnectionMonitor.h | 54 - .../linux/LNetworkConnectionMonitor_linux.cpp | 86 -- .../src/ws/mac/MNetworkConnectionMonitor.h | 52 - .../ws/mac/MNetworkConnectionMonitor_mac.cpp | 70 -- thirdparty/liblastfm2/src/ws/mac/ProxyDict.h | 75 -- thirdparty/liblastfm2/src/ws/win/ComSetup.h | 64 -- thirdparty/liblastfm2/src/ws/win/IeSettings.h | 43 - .../liblastfm2/src/ws/win/NdisEvents.cpp | 87 -- thirdparty/liblastfm2/src/ws/win/NdisEvents.h | 44 - thirdparty/liblastfm2/src/ws/win/Pac.cpp | 129 --- thirdparty/liblastfm2/src/ws/win/Pac.h | 52 - .../src/ws/win/WNetworkConnectionMonitor.h | 44 - .../ws/win/WNetworkConnectionMonitor_win.cpp | 67 -- thirdparty/liblastfm2/src/ws/win/WmiSink.cpp | 202 ---- thirdparty/liblastfm2/src/ws/win/WmiSink.h | 49 - thirdparty/liblastfm2/src/ws/ws.cpp | 237 ----- thirdparty/liblastfm2/src/ws/ws.h | 149 --- thirdparty/liblastfm2/tests/TestTrack.h | 35 - thirdparty/liblastfm2/tests/TestUrlBuilder.h | 80 -- thirdparty/liblastfm2/tests/main.cpp | 22 - thirdparty/liblastfm2/tests/tests.pro | 4 - 108 files changed, 15108 deletions(-) delete mode 100644 thirdparty/liblastfm2/CMakeLists.txt delete mode 100644 thirdparty/liblastfm2/COPYING delete mode 100644 thirdparty/liblastfm2/README.md delete mode 100644 thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake delete mode 100644 thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake delete mode 100644 thirdparty/liblastfm2/demos/demo1.cpp delete mode 100644 thirdparty/liblastfm2/demos/demo2.cpp delete mode 100644 thirdparty/liblastfm2/demos/demo3.cpp delete mode 100644 thirdparty/liblastfm2/demos/demos.pro delete mode 100644 thirdparty/liblastfm2/lastfm.pro delete mode 100644 thirdparty/liblastfm2/src/CMakeLists.txt delete mode 100644 thirdparty/liblastfm2/src/core/README delete mode 100644 thirdparty/liblastfm2/src/core/UrlBuilder.cpp delete mode 100644 thirdparty/liblastfm2/src/core/UrlBuilder.h delete mode 100644 thirdparty/liblastfm2/src/core/XmlQuery.cpp delete mode 100644 thirdparty/liblastfm2/src/core/XmlQuery.h delete mode 100644 thirdparty/liblastfm2/src/core/misc.cpp delete mode 100644 thirdparty/liblastfm2/src/core/misc.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt delete mode 100644 thirdparty/liblastfm2/src/fingerprint/Collection.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/Collection.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/Fingerprint.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/Sha256.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/Sha256.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro delete mode 100644 thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fingerprint.pro delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h delete mode 100644 thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h delete mode 100644 thirdparty/liblastfm2/src/global.h delete mode 100644 thirdparty/liblastfm2/src/lastfm.pro delete mode 100755 thirdparty/liblastfm2/src/radio/RadioStation.cpp delete mode 100644 thirdparty/liblastfm2/src/radio/RadioStation.h delete mode 100644 thirdparty/liblastfm2/src/radio/RadioTuner.cpp delete mode 100644 thirdparty/liblastfm2/src/radio/RadioTuner.h delete mode 100644 thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp delete mode 100644 thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h delete mode 100644 thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp delete mode 100644 thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h delete mode 100644 thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h delete mode 100755 thirdparty/liblastfm2/src/types/AbstractType.h delete mode 100644 thirdparty/liblastfm2/src/types/Album.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Album.h delete mode 100644 thirdparty/liblastfm2/src/types/Artist.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Artist.h delete mode 100644 thirdparty/liblastfm2/src/types/FingerprintId.cpp delete mode 100644 thirdparty/liblastfm2/src/types/FingerprintId.h delete mode 100644 thirdparty/liblastfm2/src/types/Mbid.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Mbid.h delete mode 100644 thirdparty/liblastfm2/src/types/Playlist.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Playlist.h delete mode 100644 thirdparty/liblastfm2/src/types/Tag.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Tag.h delete mode 100644 thirdparty/liblastfm2/src/types/Tasteometer.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Tasteometer.h delete mode 100644 thirdparty/liblastfm2/src/types/Track.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Track.h delete mode 100644 thirdparty/liblastfm2/src/types/User.cpp delete mode 100644 thirdparty/liblastfm2/src/types/User.h delete mode 100644 thirdparty/liblastfm2/src/types/Xspf.cpp delete mode 100644 thirdparty/liblastfm2/src/types/Xspf.h delete mode 100644 thirdparty/liblastfm2/src/types/mbid_mp3.c delete mode 100644 thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h delete mode 100644 thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/NetworkAccessManager.h delete mode 100644 thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h delete mode 100644 thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h delete mode 100644 thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h delete mode 100644 thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/mac/ProxyDict.h delete mode 100644 thirdparty/liblastfm2/src/ws/win/ComSetup.h delete mode 100644 thirdparty/liblastfm2/src/ws/win/IeSettings.h delete mode 100644 thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/win/NdisEvents.h delete mode 100644 thirdparty/liblastfm2/src/ws/win/Pac.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/win/Pac.h delete mode 100755 thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h delete mode 100755 thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/win/WmiSink.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/win/WmiSink.h delete mode 100644 thirdparty/liblastfm2/src/ws/ws.cpp delete mode 100644 thirdparty/liblastfm2/src/ws/ws.h delete mode 100644 thirdparty/liblastfm2/tests/TestTrack.h delete mode 100644 thirdparty/liblastfm2/tests/TestUrlBuilder.h delete mode 100644 thirdparty/liblastfm2/tests/main.cpp delete mode 100644 thirdparty/liblastfm2/tests/tests.pro diff --git a/thirdparty/liblastfm2/CMakeLists.txt b/thirdparty/liblastfm2/CMakeLists.txt deleted file mode 100644 index b0f71bd5d..000000000 --- a/thirdparty/liblastfm2/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -set( CMAKE_MODULE_PATH - ${CMAKE_MODULE_PATH} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules - ) - -if(${CMAKE_BUILD_TYPE} MATCHES "Release") - add_definitions(-DNDEBUG) -endif(${CMAKE_BUILD_TYPE} MATCHES "Release") - -# Set up definitions and paths -add_definitions(${QT_DEFINITIONS}) -include(${QT_USE_FILE}) - -# Main Library -add_subdirectory(src) - -# Optionally build the fingerprint library -option(BUILD_FINGERPRINT "Build the lastfm-fingerprint library" OFF) -find_package(LibSamplerate) -find_package(LibFFTW3) - -if (BUILD_FINGERPRINT AND LIBFFTW3_FOUND AND LIBSAMPLERATE_FOUND) - add_subdirectory(src/fingerprint) -endif (BUILD_FINGERPRINT AND LIBFFTW3_FOUND AND LIBSAMPLERATE_FOUND) - diff --git a/thirdparty/liblastfm2/COPYING b/thirdparty/liblastfm2/COPYING deleted file mode 100644 index 94a045322..000000000 --- a/thirdparty/liblastfm2/COPYING +++ /dev/null @@ -1,621 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS diff --git a/thirdparty/liblastfm2/README.md b/thirdparty/liblastfm2/README.md deleted file mode 100644 index 4132ce5ea..000000000 --- a/thirdparty/liblastfm2/README.md +++ /dev/null @@ -1,126 +0,0 @@ -liblastfm -========= -liblastfm is a collection of libraries to help you integrate Last.fm services -into your rich desktop software. It is officially supported software developed -by Last.fm staff. - -Michael Coffey http://twitter.com/eartle - -Fork it: http://github.com/eartle/liblastfm - - -Dependencies -============ -liblastfm dynamically links to: - -* Qt 4.8 - http://qt.nokia.com/ -* FFTW 3.2 - Compiled with single precision - http://www.fftw.org -* Secret Rabbit code (aka libsamplerate) - http://www.mega-nerd.com/SRC - -Additionally, to build you will need Ruby and GNU make (or Microsoft nmake). - -Mac OS X --------- - sudo port selfupdate - sudo port upgrade installed - sudo port install libsamplerate fftw-3 qt4-mac-devel - -Linux/*NIX ----------- -Do something like this: - - sudo apt-get install qt4-qmake pkg-config libsamplerate-dev libfftw3-dev ruby g++ libqt4-dev - -Additionally on Linux the configure process requires lsb_release. This is -usually already installed (correct me if I'm wrong). - -Please note, we have only tested on Linux, but we think it'll work on all -varieties of UNIX. If it doesn't, report the bug to eartle on GitHub. - -Windows -------- -Install Ruby. Install Visual Studio 2008 or higher. Install Qt. Install the -Windows Server 2003 Platform SDK r2: - -http://www.microsoft.com/Downloads/details.aspx?FamilyID=484269e2-3b89-47e3-8eb7-1f2be6d7123a - -Set up your environment variables so all include paths and tools are -available. - -Build and install FFTW and Secret Rabbit Code. - -Open a plain Windows shell (Cygwin will work but we don't recommend it), and -see the next section. - - -Installing liblastfm -==================== - qmake && make && sudo make install - -Packaging liblastfm -------------------- -liblastfm builds to two dynamic libraries (liblastfm.so and -liblastfm_fingerprint.so). liblastfm.so links only to Qt, but the -fingerprinting part has additional dependencies. So ideally, you would -distribute two packages. - - -Using liblastfm -=============== -We have copied the API at http://last.fm/api onto C++, so like you find -artist.getInfo there you will find an lastfm::Artist::getInfo function in our -C++ API. lastfm is a namespace, Artist a class and getInfo a function. - -Thus the API is quite easy to learn. We suggest installing and checking the -include/lastfm/* directory to find out all capabilities. - -The demos directory shows some further basic usage including Audioscrobbling -and getting metadata for music via our fingerprinting technology. - -You need an API key from http://last.fm/api to use the webservice API. - -Your link line needs to include the following: - - -llastfm -lQtCore -lQtNetwork -lQtXml - -Radio ------ -Please set an identifiable UserAgent on your HTTP requests for the actual MP3s, -in extreme cases we'll contact you directly and demand you do so :P - -HTTP & Networking ------------------ -You can specify your own QNetworkAccessManager derived class for liblastfm to -use with lastfm::setNetworkAccessManager(). Our default is pretty good -though, auto-determining proxy settings on Windows and OS X for instance. - - -Using liblastfm_fingerprint -=========================== -The liblastfm_fingerprint library does not decode audio files. We anticipate -that Phonon will soon do that work for us. In the meantime, sample *Source -files for MP3, Ogg Vorbis, FLAC, and AAC/MP4 are available in -src/fingerprint/contrib. If you want to fingerprint files or get metadata -suggestions, you either need to add the *Source files to your project, or -implement your own. - - -Development -=========== -Public Headers --------------- -1. Header guards should be prefixed with LASTFM, eg. LASTFM_WS_REPLY_H -2. #includes should be to the system path eg. #include -3. Don't make a header public unless it is absolutely required! -4. To make the header public edit the headers.files line in the pro file - -Private Headers ---------------- -1. For consistency and to make it more obvious it is a private header, don't - prefix the header guard with LASTFM -2. #includes should be the full source tree path, eg. - #include "../core/UrlBuilder.h" diff --git a/thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake b/thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake deleted file mode 100644 index fa6419a2b..000000000 --- a/thirdparty/liblastfm2/cmake/modules/FindLibFFTW3.cmake +++ /dev/null @@ -1,45 +0,0 @@ -# This file is copyrighted under the BSD-license for buildsystem files of KDE -# copyright 2010, Patrick von Reth -# -# -# - Try to find the LIBFFTW3 library -# Once done this will define -# -# LIBFFTW3_FOUND Set to TRUE if LIBFFTW3 librarys and include directory is found -# LIBFFTW3_INCLUDE_DIR The libfftw3 include directory -# LIBFFTW3_LIBRARY The libfftw3 librarys - -if(NOT LIBFFTW3_PRECISION) - message(STATUS "Searching for LIBFFTW3, using default precision float") - set(LIBFFTW3_PRECISION FLOAT) -endif(NOT LIBFFTW3_PRECISION) - -find_path(LIBFFTW3_INCLUDE_DIR fftw3.h) - -if(LIBFFTW3_PRECISION STREQUAL FLOAT) - set(LIBFFTW3_PRECISION_SUFFIX f) -endif(LIBFFTW3_PRECISION STREQUAL FLOAT) - -if(LIBFFTW3_PRECISION STREQUAL DOUBLE) - set(LIBFFTW3_PRECISION_SUFFIX "") -endif(LIBFFTW3_PRECISION STREQUAL DOUBLE) - -if(LIBFFTW3_PRECISION STREQUAL LDOUBLE) - set(LIBFFTW3_PRECISION_SUFFIX l) -endif(LIBFFTW3_PRECISION STREQUAL LDOUBLE) - -find_library(LIBFFTW3_LIBRARY NAMES fftw3${LIBFFTW3_PRECISION_SUFFIX} libfftw3${LIBFFTW3_PRECISION_SUFFIX}-3 fftw3${LIBFFTW3_PRECISION_SUFFIX}-3) - -if(FIND_LIBFFTW3_VERBOSE) - message(STATUS - "LIBFFTW3_PRECISION ${LIBFFTW3_PRECISION}, searched for fftw3${LIBFFTW3_PRECISION_SUFFIX} libfftw3${LIBFFTW3_PRECISION_SUFFIX}-3 fftw3${LIBFFTW3_PRECISION_SUFFIX}-3 - and found ${LIBFFTW3_LIBRARY}" - ) -endif(FIND_LIBFFTW3_VERBOSE) - -if(LIBFFTW3_LIBRARY AND LIBFFTW3_INCLUDE_DIR) - set(LIBFFTW3_FOUND TRUE) - message(STATUS "Found libfftw3 ${LIBFFTW3_LIBRARY}") -else(LIBFFTW3_LIBRARY AND LIBFFTW3_PLUGIN_PATH) - message(STATUS "Could not find libfftw3, get it http://www.fftw.org/") -endif(LIBFFTW3_LIBRARY AND LIBFFTW3_INCLUDE_DIR) diff --git a/thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake b/thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake deleted file mode 100644 index d77536b2f..000000000 --- a/thirdparty/liblastfm2/cmake/modules/FindLibSamplerate.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# This file is copyrighted under the BSD-license for buildsystem files of KDE -# copyright 2010, Patrick von Reth -# -# -# - Try to find the libsamplerate library -# Once done this will define -# -# LIBSAMPLERATE_FOUND Set to TRUE if libsamplerate librarys and include directory is found -# LIBSAMPLERATE_LIBRARY The libsamplerate librarys -# LIBSAMPLERATE_INCLUDE_DIR The libsamplerate include directory - - -find_library(LIBSAMPLERATE_LIBRARY NAMES samplerate libsamplerate-0 samplerate-0) - -find_path(LIBSAMPLERATE_INCLUDE_DIR samplerate.h) - -if(LIBSAMPLERATE_LIBRARY AND LIBSAMPLERATE_INCLUDE_DIR) - set(LIBSAMPLERATE_FOUND TRUE) - message(STATUS "Found libsamplerate ${LIBSAMPLERATE_LIBRARY}") -else(LIBSAMPLERATE_LIBRARY AND LIBSAMPLERATE_PLUGIN_PATH) - message(STATUS "Could not find libsamplerate, get it http://www.mega-nerd.com/SRC/") -endif(LIBSAMPLERATE_LIBRARY AND LIBSAMPLERATE_INCLUDE_DIR) diff --git a/thirdparty/liblastfm2/demos/demo1.cpp b/thirdparty/liblastfm2/demos/demo1.cpp deleted file mode 100644 index b0fd8df99..000000000 --- a/thirdparty/liblastfm2/demos/demo1.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include // this includes everything in liblastfm, you may prefer -#include // to just include what you need with your project. Still -#include // we've given you the option. -#include -#include - -class ArtistList : public QListWidget -{ - Q_OBJECT - - QPointer reply; - QString artist; - -public: - ArtistList() - { - connect( this, - SIGNAL(itemActivated( QListWidgetItem* )), - SLOT(onItemActivated( QListWidgetItem* )) ); - } - - void getSimilar( const QString& artist ) - { - this->artist = artist; - setWindowTitle( "Loading " + artist + "..." ); - - // deleting a reply cancels the request and disconnects all signals - delete reply; - reply = lastfm::Artist( artist ).getSimilar(); - connect( reply, SIGNAL(finished()), SLOT(onGotSimilar()) ); - } - -private slots: - void onGotSimilar() - { - QNetworkReply* r = static_cast(sender()); - // always enclose retrieval functions in a try block, as they will - // throw if they can't parse the data - try - { - // you decode the response using the equivalent static function - QMap artists = lastfm::Artist::getSimilar( r ); - - clear(); - - // we iterate backwards because best match is last because the map - // sorts itself by key - QStringListIterator i( artists.values() ); - i.toBack(); - while (i.hasPrevious()) - addItem( i.previous() ); - - setWindowTitle( artist ); - } - catch (std::runtime_error& e) - { - // if getSimilar() failed to parse the QNetworkReply, then e will - // be of type lastfm::ws::ParseError, which derives - // std::runtime_error - qWarning() << e.what(); - } - } - - void onItemActivated( QListWidgetItem* item ) - { - getSimilar( item->text() ); - } -}; - - -int main( int argc, char** argv ) -{ - QApplication app( argc, argv ); - app.setApplicationName( "liblastfm" ); // used to generate UserAgent - - // all you need for non-authenticated webservices is your API key - // this one is a public one, it can only do artist.getSimilar calls, so - // I suggest you don't use it :P - lastfm::ws::ApiKey = "b25b959554ed76058ac220b7b2e0a026"; - - ArtistList artists; - artists.getSimilar( "nirvana" ); - artists.resize( 300, 400 ); // Qt picks truly asanine default sizes for its widgets - artists.show(); - - return app.exec(); -} - - -#include "demo1.moc" diff --git a/thirdparty/liblastfm2/demos/demo2.cpp b/thirdparty/liblastfm2/demos/demo2.cpp deleted file mode 100644 index 53c9a7ec9..000000000 --- a/thirdparty/liblastfm2/demos/demo2.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include - - -struct MyCoreApp : QCoreApplication -{ - Q_OBJECT - -public: - MyCoreApp( int& argc, char**& argv ) : QCoreApplication( argc, argv ) - {} - -private slots: - void onWsError( lastfm::ws::Error e ) - { - // QNetworkReply will invoke this slot on application level errors - // mostly this is only stuff like Ws::InvalidSessionKey and - // Ws::InvalidApiKey - qWarning() << e; - } -}; - - -int main( int argc, char** argv ) -{ - MyCoreApp app( argc, argv ); - // this is used to generate the UserAgent for webservice requests - // please set it to something sensible in your application - app.setApplicationName( "liblastfm" ); - -////// you'll need to fill these in for this demo to work - lastfm::ws::Username = - lastfm::ws::ApiKey = - lastfm::ws::SharedSecret = - QString password = - -////// Usually you never have to construct an Last.fm WS API call manually - // eg. Track.getTopTags() just returns a QNetworkReply* but authentication is - // different. - // We're using getMobileSession here as we're a console app, but you - // should use getToken if you can as the user will be presented with a - // route that feels my trustworthy to them than entering their password - // into some random app they just downloaded... ;) - QMap params; - params["method"] = "auth.getMobileSession"; - params["username"] = lastfm::ws::Username; - params["authToken"] = lastfm::md5( (lastfm::ws::Username + lastfm::md5( password.toUtf8() )).toUtf8() ); - QNetworkReply* reply = lastfm::ws::post( params ); - - // never do this when an event loop is running it's a real HACK - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); - - try - { - ////// Usually there is a convenience function to decode the output from - // ws calls too, but again, authentication is different. We think you - // need to handle it yourselves :P Also conveniently it means you - // can learn more about what our webservices return, eg. this service - // will return an XML document like this: - // - // - // - // mxcl - // d580d57f32848f5dcf574d1ce18d78b2 - // 1 - // - // - // - // If status is not "ok" then this function throws - lastfm::XmlQuery const lfm = lastfm::ws::parse( reply ); - - // replace username; because eg. perhaps the user typed their - // username with the wrong case - lastfm::ws::Username = lfm["session"]["name"].text(); - - // we now have a session key, you should save this, forever! Really. - // DO NOT AUTHENTICATE EVERY TIME THE APP STARTS! You only have to do - // this once. Or again if the user deletes your key on the site. If - // that happens you'll get notification to your onWsError() function, - // see above. - lastfm::ws::SessionKey = lfm["session"]["key"].text(); - - qDebug() << "sk:" << lastfm::ws::SessionKey; - - ////// because the SessionKey is now set, the AuthenticatedUser class will - // work. And we can call authenticated calls - QNetworkReply* reply = lastfm::AuthenticatedUser().getRecommendedArtists(); - - // again, you shouldn't do this.. ;) - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); - - // yay, a list rec'd artists to stderr :) - qDebug() << lastfm::Artist::list( reply ); - } - catch (std::runtime_error& e) - { - // lastfm::ws::parse() can throw lastfm::ws::ParseError, this - // exception derives std::runtime_error - qWarning() << e.what(); - return 1; - } -} - - -#include "demo2.moc" diff --git a/thirdparty/liblastfm2/demos/demo3.cpp b/thirdparty/liblastfm2/demos/demo3.cpp deleted file mode 100644 index 2bf3c1db3..000000000 --- a/thirdparty/liblastfm2/demos/demo3.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -#include -#include "src/_version.h" - - -struct MyCoreApp : QCoreApplication -{ - Q_OBJECT - -public: - MyCoreApp( int& argc, char** argv ) : QCoreApplication( argc, argv ) - {} - -public slots: - void onStatus( int status ) - { - qDebug() << lastfm::Audioscrobbler::Status(status); - } -}; - - -int main( int argc, char** argv ) -{ - // all 6 of these lines are REQUIRED in order to scrobble - // this demo requires you to fill in the blanks as well... - lastfm::ws::Username = - lastfm::ws::ApiKey = - lastfm::ws::SharedSecret = - lastfm::ws::SessionKey = // you need to auth to get this... try demo2 - QCoreApplication::setApplicationName( "liblastfm" ); - QCoreApplication::setApplicationVersion( VERSION ); - - MyCoreApp app( argc, argv ); - - lastfm::MutableTrack t; - t.setArtist( "Max Howell" ); - t.setTitle( "I Told You Not To Trust Me With Your Daughter" ); - t.setDuration( 30 ); - t.stamp(); //sets track start time - - lastfm::Audioscrobbler as( "ass" ); - as.nowPlaying( t ); - // Audioscrobbler will submit whatever is in the cache when you call submit. - // And the cache is persistent between sessions. So you should cache at the - // scrobble point usually, not before - as.cache( t ); - - //FIXME I don't get it, but the timer never triggers! pls fork and fix! - QTimer::singleShot( 31*1000, &as, SLOT(submit()) ); - - app.connect( &as, SIGNAL(status(int)), SLOT(onStatus(int)) ); - - return app.exec(); -} - - -#include "demo3.moc" diff --git a/thirdparty/liblastfm2/demos/demos.pro b/thirdparty/liblastfm2/demos/demos.pro deleted file mode 100644 index 356edff74..000000000 --- a/thirdparty/liblastfm2/demos/demos.pro +++ /dev/null @@ -1,3 +0,0 @@ -QT = core gui network xml -LIBS += -llastfm -L$$DESTDIR -SOURCES = demo1.cpp # change to demo2.cpp (etc.) to compile that demo diff --git a/thirdparty/liblastfm2/lastfm.pro b/thirdparty/liblastfm2/lastfm.pro deleted file mode 100644 index 32839418e..000000000 --- a/thirdparty/liblastfm2/lastfm.pro +++ /dev/null @@ -1,142 +0,0 @@ -TEMPLATE = lib -CONFIG += dll -QT = core network xml - -ROOT_DIR = . - -BUILD_DIR = _build -DESTDIR = $$ROOT_DIR/_bin - -OBJECTS_DIR = $$BUILD_DIR -MOC_DIR = $$BUILD_DIR -UI_DIR = $$BUILD_DIR -RCC_DIR = $$BUILD_DIR -INCLUDEPATH += $$ROOT_DIR/_include - -win32:DEFINES += _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN - -mac { - QMAKE_PKGINFO_TYPEINFO = last - QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 -} - -*g++* { - # allow use of 'and', 'or', etc. as symbols - QMAKE_CXXFLAGS += -fno-operator-names - QMAKE_CXXFLAGS_RELEASE += -fvisibility-inlines-hidden -fvisibility=hidden -} - -# used to determine if we should statically link the fingerprint library -# used by lastfm-desktop and other projects -CONFIG -= app_bundle - -win32{ -INSTALLS = headers -headers.path = _include/lastfm -headers.files = src/*.h -} -else{ - isEmpty( PREFIX ) { - PREFIX=/usr/local - } -INSTALLS = target headers -target.path = $${PREFIX}/lib -headers.path = $${PREFIX}/include/lastfm -headers.files = src/*.h -} - -INCLUDEPATH += src - -win32{ - DEFINES += LASTFM_LIB _ATL_DLL - LIBS += winhttp.lib wbemuuid.lib # ws configuration -} -mac{ - LIBS += -framework SystemConfiguration # ws configuration - #TODO we should only use these with the carbon version of Qt! - LIBS += -framework CoreFoundation # various -} - -unix:!mac{ - QT += dbus -} - -SOURCES += \ - src/ws.cpp \ - src/NetworkConnectionMonitor.cpp \ - src/NetworkAccessManager.cpp \ - src/InternetConnectionMonitor.cpp \ - src/Xspf.cpp \ - src/User.cpp \ - src/Track.cpp \ - src/Tasteometer.cpp \ - src/Tag.cpp \ - src/Playlist.cpp \ - src/Mbid.cpp \ - src/FingerprintId.cpp \ - src/Artist.cpp \ - src/Album.cpp \ - src/ScrobbleCache.cpp \ - src/ScrobblePoint.cpp \ - src/Audioscrobbler.cpp \ - src/RadioTuner.cpp \ - src/RadioStation.cpp \ - src/XmlQuery.cpp \ - src/UrlBuilder.cpp \ - src/misc.cpp \ - src/Chart.cpp \ - src/Auth.cpp \ - src/Library.cpp - -HEADERS += \ - src/ws.h \ - src/NetworkConnectionMonitor.h \ - src/NetworkAccessManager.h \ - src/InternetConnectionMonitor.h \ - src/Xspf.h \ - src/User.h \ - src/Track.h \ - src/Tasteometer.h \ - src/Tag.h \ - src/Playlist.h \ - src/Mbid.h \ - src/FingerprintId.h \ - src/Artist.h \ - src/Album.h \ - src/AbstractType.h \ - src/ScrobblePoint.h \ - src/ScrobbleCache.h \ - src/Audioscrobbler.h \ - src/RadioTuner.h \ - src/RadioStation.h \ - src/global.h \ - src/XmlQuery.h \ - src/UrlBuilder.h \ - src/misc.h \ - src/Chart.h \ - src/Auth.h \ - src/Library.h - -win32:SOURCES += src/win/WNetworkConnectionMonitor_win.cpp \ - src/win/WmiSink.cpp \ - src/win/Pac.cpp \ - src/win/NdisEvents.cpp - -win32:HEADERS += src/win/WNetworkConnectionMonitor.h \ - src/win/WmiSink.h \ - src/win/Pac.h \ - src/win/NdisEvents.h \ - src/win/IeSettings.h \ - src/win/ComSetup.h - -mac:SOURCES += src/mac/MNetworkConnectionMonitor_mac.cpp - -mac:HEADERS += src/mac/ProxyDict.h \ - src/mac/MNetworkConnectionMonitor.h - -unix:!mac:SOURCES += src/linux/LNetworkConnectionMonitor_linux.cpp -unix:!mac:HEADERS += src/linux/LNetworkConnectionMonitor.h - -!win32:VERSION = 1.0.0 - - diff --git a/thirdparty/liblastfm2/src/CMakeLists.txt b/thirdparty/liblastfm2/src/CMakeLists.txt deleted file mode 100644 index 56c203c14..000000000 --- a/thirdparty/liblastfm2/src/CMakeLists.txt +++ /dev/null @@ -1,125 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -# Macro to copy and rename headers -macro(copy_header from to) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/${from} - ${CMAKE_CURRENT_BINARY_DIR}/lastfm/${to} - COPY_ONLY - ) -endmacro(copy_header) - -# Copy headers -copy_header(core/misc.h misc.h) -copy_header(core/XmlQuery.h XmlQuery) -copy_header(core/UrlBuilder.h UrlBuilder) -copy_header(global.h global.h) -copy_header(radio/RadioTuner.h RadioTuner) -copy_header(radio/RadioStation.h RadioStation) -copy_header(scrobble/Audioscrobbler.h Audioscrobbler) -copy_header(scrobble/ScrobbleCache.h ScrobbleCache) -copy_header(scrobble/ScrobblePoint.h ScrobblePoint) -copy_header(types/AbstractType.h AbstractType) -copy_header(types/Album.h Album) -copy_header(types/Artist.h Artist) -copy_header(types/FingerprintId.h FingerprintId) -copy_header(types/Mbid.h Mbid) -copy_header(types/Playlist.h Playlist) -copy_header(types/Tag.h Tag) -copy_header(types/Track.h Track) -copy_header(types/User.h User) -copy_header(types/User.h UserList) -copy_header(types/Xspf.h Xspf) -copy_header(ws/ws.h ws.h) -copy_header(ws/InternetConnectionMonitor.h InternetConnectionMonitor) -copy_header(ws/NetworkAccessManager.h NetworkAccessManager) - -include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) - -set(SOURCES - scrobble/ScrobbleCache.cpp - scrobble/Audioscrobbler.cpp - types/FingerprintId.cpp - types/Artist.cpp - types/Tag.cpp - types/Track.cpp - types/User.cpp - types/Xspf.cpp - types/Album.cpp - types/Playlist.cpp - types/Mbid.cpp - radio/RadioTuner.cpp - radio/RadioStation.cpp - core/UrlBuilder.cpp - core/misc.cpp - core/XmlQuery.cpp - ws/NetworkAccessManager.cpp - ws/ws.cpp - ws/InternetConnectionMonitor.cpp - ws/NetworkConnectionMonitor.cpp -) - -set(MOC_HEADERS - scrobble/Audioscrobbler.h - types/Track.h - types/Xspf.h - radio/RadioTuner.h - ws/NetworkConnectionMonitor.h - ws/InternetConnectionMonitor.h - ws/NetworkAccessManager.h -) - -if(UNIX) - if(APPLE) - set(SOURCES ${SOURCES} ws/mac/MNetworkConnectionMonitor_mac.cpp) - set(MOC_HEADERS ${MOC_HEADERS} ws/mac/MNetworkConnectionMonitor.h) - else(APPLE) - set(SOURCES ${SOURCES} ws/linux/LNetworkConnectionMonitor_linux.cpp) - set(MOC_HEADERS ${MOC_HEADERS} ws/linux/LNetworkConnectionMonitor.h) - endif(APPLE) -endif(UNIX) -if(WIN32) - set(SOURCES ${SOURCES} ws/win/WNetworkConnectionMonitor_win.cpp ws/win/Pac.cpp ws/win/NdisEvents.cpp ) - set(MOC_HEADERS ${MOC_HEADERS} ws/win/WNetworkConnectionMonitor.h) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../winhttp) -endif(WIN32) - -qt4_wrap_cpp(MOC_SOURCES ${MOC_HEADERS}) - -IF( WIN32 ) - add_definitions( -DLASTFM_LIB ) - add_library(tomahawk_lastfm2 SHARED - ${SOURCES} - ${MOC_SOURCES} - ) -ELSE() - add_definitions(-fPIC) - add_library(tomahawk_lastfm2 STATIC - ${SOURCES} - ${MOC_SOURCES} - ) -ENDIF() - -target_link_libraries(tomahawk_lastfm2 - ${QT_LIBRARIES} - ${QT_QTDBUS_LIBRARY} - -) - -set_target_properties(tomahawk_lastfm2 PROPERTIES COMPILE_FLAGS "-DLASTFM_OHAI_QMAKE" ) - -if(APPLE) - target_link_libraries(tomahawk_lastfm2 - /System/Library/Frameworks/CoreFoundation.framework - /System/Library/Frameworks/SystemConfiguration.framework - ) -endif(APPLE) - - -IF( WIN32 ) - install(TARGETS tomahawk_lastfm2 - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib${LIB_SUFFIX} - ARCHIVE DESTINATION lib${LIB_SUFFIX} - ) -ENDIF() diff --git a/thirdparty/liblastfm2/src/core/README b/thirdparty/liblastfm2/src/core/README deleted file mode 100644 index b725eac20..000000000 --- a/thirdparty/liblastfm2/src/core/README +++ /dev/null @@ -1,8 +0,0 @@ -Files in lastfm-core are basically extensions to fundamental Qt classes. -They may be useful to you, but mainly they are here because they are useful to -liblastfm in general. - -A lot of the time they are convenience functions that hopefully at some point -Qt will make obsolete. - - diff --git a/thirdparty/liblastfm2/src/core/UrlBuilder.cpp b/thirdparty/liblastfm2/src/core/UrlBuilder.cpp deleted file mode 100644 index 1e0171aa1..000000000 --- a/thirdparty/liblastfm2/src/core/UrlBuilder.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "UrlBuilder.h" -#include -#include - - -QUrl -lastfm::UrlBuilder::url() const -{ - QUrl url; - url.setScheme( "http" ); - url.setHost( host() ); - url.setEncodedPath( path ); - return url; -} - - -QByteArray //static -lastfm::UrlBuilder::encode( QString s ) -{ - foreach (QChar c, QList() << '%' << '&' << '/' << ';' << '+' << '#' << '"') - if (s.contains( c )) - // the middle step may seem odd but this is what the site does - // eg. search for the exact string "Radiohead 2 + 2 = 5" - return QUrl::toPercentEncoding( s ).replace( "%20", "+" ).toPercentEncoding( "", "+" );; - - return QUrl::toPercentEncoding( s.replace( ' ', '+' ), "+" ); -} - - -QString //static -lastfm::UrlBuilder::host( const QLocale& locale ) -{ - switch (locale.language()) - { - case QLocale::Portuguese: return "www.lastfm.com.br"; - case QLocale::Turkish: return "www.lastfm.com.tr"; - case QLocale::French: return "www.lastfm.fr"; - case QLocale::Italian: return "www.lastfm.it"; - case QLocale::German: return "www.lastfm.de"; - case QLocale::Spanish: return "www.lastfm.es"; - case QLocale::Polish: return "www.lastfm.pl"; - case QLocale::Russian: return "www.lastfm.ru"; - case QLocale::Japanese: return "www.lastfm.jp"; - case QLocale::Swedish: return "www.lastfm.se"; - case QLocale::Chinese: return "cn.last.fm"; - default: return "www.last.fm"; - } -} - - -QUrl //static -lastfm::UrlBuilder::localize( QUrl url) -{ - url.setHost( url.host().replace( QRegExp("^(www.)?last.fm"), host() ) ); - return url; -} - - -QUrl //static -lastfm::UrlBuilder::mobilize( QUrl url ) -{ - url.setHost( url.host().replace( QRegExp("^(www.)?last"), "m.last" ) ); - return url; -} diff --git a/thirdparty/liblastfm2/src/core/UrlBuilder.h b/thirdparty/liblastfm2/src/core/UrlBuilder.h deleted file mode 100644 index 42014537c..000000000 --- a/thirdparty/liblastfm2/src/core/UrlBuilder.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_URL_BUILDER_H -#define LASTFM_URL_BUILDER_H - -#include -#include -#include -#include - - -namespace lastfm -{ - /** For building www.last.fm urls. We have special rules for encoding and that */ - class LASTFM_DLLEXPORT UrlBuilder - { - QByteArray path; - - public: - /** Careful, the base is not encoded at all, we assume it is ASCII! - * If you need it encoded at all you must use the slash function. - * eg. UrlBuilder( "user" ).slash( "mxcl" ) ==> http://last.fm/user/mxcl - */ - UrlBuilder( const QString& base ) : path( '/' + base.toAscii() ) - {} - - UrlBuilder& slash( const QString& path ) { this->path += '/' + encode( path ); return *this; } - - QUrl url() const; - - /** www.last.fm becomes the local version, eg www.lastfm.de */ - static QUrl localize( QUrl ); - /** www.last.fm becomes m.last.fm, localisation is preserved */ - static QUrl mobilize( QUrl ); - - /** Use this to URL encode any database item (artist, track, album). It - * internally calls UrlEncodeSpecialChars to double encode some special - * symbols according to the same pattern as that used on the website. - * - * &, /, ;, +, # - * - * Use for any urls that go to www.last.fm - * Do not use for ws.audioscrobbler.com - */ - static QByteArray encode( QString ); - - /** returns eg. www.lastfm.de */ - static QString host( const QLocale& = QLocale() ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/core/XmlQuery.cpp b/thirdparty/liblastfm2/src/core/XmlQuery.cpp deleted file mode 100644 index b443e94b7..000000000 --- a/thirdparty/liblastfm2/src/core/XmlQuery.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "XmlQuery.h" - -#include -#include - -using lastfm::XmlQuery; - - -XmlQuery::XmlQuery( const QByteArray& bytes ) throw( lastfm::ws::ParseError ) -{ - try - { - if ( !bytes.size() ) - throw lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "No data" ); - - if( !domdoc.setContent( bytes ) ) - throw lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "Invalid XML" ); - - e = domdoc.documentElement(); - - if (e.isNull()) - throw lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "Lfm is null" ); - - QString const status = e.attribute( "status" ); - QDomElement error = e.firstChildElement( "error" ); - uint const n = e.childNodes().count(); - - // no elements beyond the lfm is perfectably acceptable <-- wtf? - // if (n == 0) // nothing useful in the response - if (status == "failed" || (n == 1 && !error.isNull()) ) - throw error.isNull() - ? lastfm::ws::ParseError( lastfm::ws::MalformedResponse, "" ) - : lastfm::ws::ParseError( lastfm::ws::Error( error.attribute( "code" ).toUInt() ), error.text() ); - - } - catch ( lastfm::ws::ParseError e ) - { - switch ( e.enumValue() ) - { - case lastfm::ws::OperationFailed: - case lastfm::ws::InvalidApiKey: - case lastfm::ws::InvalidSessionKey: - // NOTE will never be received during the LoginDialog stage - // since that happens before this slot is registered with - // QMetaObject in App::App(). Neat :) - QMetaObject::invokeMethod( qApp, "onWsError", Q_ARG( lastfm::ws::Error, e.enumValue() ) ); - default: - throw e; - } - } -} - - -XmlQuery -XmlQuery::operator[]( const QString& name ) const -{ - QStringList parts = name.split( ' ' ); - if (parts.size() >= 2) - { - QString tagName = parts[0]; - parts = parts[1].split( '=' ); - QString attributeName = parts.value( 0 ); - QString attributeValue = parts.value( 1 ); - - foreach (XmlQuery e, children( tagName )) - if (e.e.attribute( attributeName ) == attributeValue) - return e; - } - XmlQuery xq( e.firstChildElement( name ), name.toUtf8().data() ); - xq.domdoc = this->domdoc; - return xq; -} - - -QList -XmlQuery::children( const QString& named ) const -{ - QList elements; - QDomNodeList nodes = e.elementsByTagName( named ); - for (int x = 0; x < nodes.count(); ++x) { - XmlQuery xq( nodes.at( x ).toElement() ); - xq.domdoc = this->domdoc; - elements += xq; - } - return elements; -} diff --git a/thirdparty/liblastfm2/src/core/XmlQuery.h b/thirdparty/liblastfm2/src/core/XmlQuery.h deleted file mode 100644 index 564e0fb38..000000000 --- a/thirdparty/liblastfm2/src/core/XmlQuery.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_XMLQUERY_H -#define LASTFM_XMLQUERY_H - -#include -#include -#include -#include - -namespace lastfm -{ - /** Qt's XmlQuery implementation is totally unimpressive, so this is a - * hack that feels like jQuery */ - class LASTFM_DLLEXPORT XmlQuery - { - QDomDocument domdoc; - QDomElement e; - - public: - /** we assume the bytearray is an XML document, this object will then - * represent the documentElement of that document, eg. if this is a - * Last.fm webservice response: - * - * XmlQuery xq = lastfm::ws::parse(response); - * qDebug() << xq["artist"].text() - * - * Notice the lfm node is not referenced, that is because it is the - * document-element of the XML document. - */ - XmlQuery( const QByteArray& ) throw( lastfm::ws::ParseError ); - - XmlQuery( const QDomElement& e, const char* name = "" ) : e( e ) - { - if (e.isNull()) qWarning() << "Expected node absent:" << name; - } - - /** Selects a DIRECT child element, you can specify attributes like so: - * - * e["element"]["element attribute=value"].text(); - */ - XmlQuery operator[]( const QString& name ) const; - QString text() const { return e.text(); } - QString attribute( const QString& name ) const{ return e.attribute( name ); } - - /** selects all children with specified name, recursively */ - QList children( const QString& named ) const; - - operator QDomElement() const { return e; } - }; -} - -inline QDebug operator<<( QDebug d, const lastfm::XmlQuery& xq ) -{ - QString s; - QTextStream t( &s, QIODevice::WriteOnly ); - QDomElement(xq).save( t, 2 ); - return d << s; -} - -#endif diff --git a/thirdparty/liblastfm2/src/core/misc.cpp b/thirdparty/liblastfm2/src/core/misc.cpp deleted file mode 100644 index 2f4a28424..000000000 --- a/thirdparty/liblastfm2/src/core/misc.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "misc.h" -#include -#ifdef WIN32 - #include -#endif -#ifdef Q_WS_MAC - #include -#endif - - -#ifdef Q_WS_MAC -QDir -lastfm::dir::bundle() -{ - // Trolltech provided example - CFURLRef appUrlRef = CFBundleCopyBundleURL( CFBundleGetMainBundle() ); - CFStringRef macPath = CFURLCopyFileSystemPath( appUrlRef, kCFURLPOSIXPathStyle ); - QString path = CFStringToQString( macPath ); - CFRelease(appUrlRef); - CFRelease(macPath); - return QDir( path ); -} -#endif - - -static QDir dataDotDot() -{ -#ifdef WIN32 - if ((QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) == 0) - { - // Use this for non-DOS-based Windowses - char path[MAX_PATH]; - HRESULT h = SHGetFolderPathA( NULL, - CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, - NULL, - 0, - path ); - if (h == S_OK) - return QString::fromLocal8Bit( path ); - } - return QDir::home(); - -#elif defined(Q_WS_MAC) - return QDir::home().filePath( "Library/Application Support" ); - -#elif defined(Q_WS_X11) - return QDir::home().filePath( ".local/share" ); - -#else - return QDir::home(); -#endif -} - - -QDir -lastfm::dir::runtimeData() -{ - return dataDotDot().filePath( "Last.fm" ); -} - - -QDir -lastfm::dir::logs() -{ -#ifdef Q_WS_MAC - return QDir::home().filePath( "Library/Logs/Last.fm" ); -#else - return runtimeData(); -#endif -} - - -QDir -lastfm::dir::cache() -{ -#ifdef Q_WS_MAC - return QDir::home().filePath( "Library/Caches/Last.fm" ); -#else - return runtimeData().filePath( "cache" ); -#endif -} - - -#ifdef WIN32 -QDir -lastfm::dir::programFiles() -{ - char path[MAX_PATH]; - - // TODO: this call is dependant on a specific version of shell32.dll. - // Need to degrade gracefully. Need to bundle SHFolder.exe with installer - // and execute it on install for this to work on Win98. - HRESULT h = SHGetFolderPathA( NULL, - CSIDL_PROGRAM_FILES, - NULL, - 0, // current path - path ); - - if (h != S_OK) - { - qCritical() << "Couldn't get Program Files dir. Possibly Win9x?"; - return QDir(); - } - - return QString::fromLocal8Bit( path ); -} -#endif - -#ifdef Q_WS_MAC -CFStringRef -lastfm::QStringToCFString( const QString &s ) -{ - return CFStringCreateWithCharacters( 0, (UniChar*)s.unicode(), s.length() ); -} - -QByteArray -lastfm::CFStringToUtf8( CFStringRef s ) -{ - QByteArray result; - - if (s != NULL) - { - CFIndex length; - length = CFStringGetLength( s ); - length = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) + 1; - char* buffer = new char[length]; - - if (CFStringGetCString( s, buffer, length, kCFStringEncodingUTF8 )) - result = QByteArray( buffer ); - else - qWarning() << "CFString conversion failed."; - - delete[] buffer; - } - - return result; -} -#endif - -#if 0 -// this is a Qt implementation I found -QString cfstring2qstring(CFStringRef str) -{ - if(!str) - return QString(); - - CFIndex length = CFStringGetLength(str); - if(const UniChar *chars = CFStringGetCharactersPtr(str)) - return QString((QChar *)chars, length); - UniChar *buffer = (UniChar*)malloc(length * sizeof(UniChar)); - CFStringGetCharacters(str, CFRangeMake(0, length), buffer); - QString ret((QChar *)buffer, length); - free(buffer); - return ret; -} -#endif diff --git a/thirdparty/liblastfm2/src/core/misc.h b/thirdparty/liblastfm2/src/core/misc.h deleted file mode 100644 index 3f41ec534..000000000 --- a/thirdparty/liblastfm2/src/core/misc.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_MISC_H -#define LASTFM_MISC_H - -#include -#include -#include -#include - -#ifdef Q_WS_MAC -typedef const struct __CFString* CFStringRef; -#endif - -namespace lastfm -{ - namespace dir - { - #ifdef Q_WS_WIN - LASTFM_DLLEXPORT QDir programFiles(); - #endif - #ifdef Q_WS_MAC - LASTFM_DLLEXPORT QDir bundle(); - #endif - LASTFM_DLLEXPORT QDir runtimeData(); - LASTFM_DLLEXPORT QDir cache(); - LASTFM_DLLEXPORT QDir logs(); - } - -#ifdef Q_WS_MAC - LASTFM_DLLEXPORT QByteArray CFStringToUtf8( CFStringRef ); - LASTFM_DLLEXPORT CFStringRef QStringToCFString( const QString& ); - inline QString CFStringToQString( CFStringRef s ); -#endif - - inline const char* platform() - { - #ifdef Q_WS_WIN - switch (QSysInfo::WindowsVersion) - { - case QSysInfo::WV_32s: return "Windows 3.1 with Win32s"; - case QSysInfo::WV_95: return "Windows 95"; - case QSysInfo::WV_98: return "Windows 98"; - case QSysInfo::WV_Me: return "Windows Me"; - case QSysInfo::WV_DOS_based: return "MS-DOS-based Windows"; - - case QSysInfo::WV_NT: return "Windows NT"; - case QSysInfo::WV_2000: return "Windows 2000"; - case QSysInfo::WV_XP: return "Windows XP"; - case QSysInfo::WV_2003: return "Windows Server 2003"; - case QSysInfo::WV_VISTA: return "Windows Vista"; - case QSysInfo::WV_NT_based: return "NT-based Windows"; - - case QSysInfo::WV_CE: return "Windows CE"; - case QSysInfo::WV_CENET: return "Windows CE.NET"; - case QSysInfo::WV_CE_based: return "CE-based Windows"; - - default: return "Unknown"; - } - #elif defined Q_WS_MAC - switch (QSysInfo::MacintoshVersion) - { - case QSysInfo::MV_Unknown: return "Unknown Mac"; - case QSysInfo::MV_9: return "Mac OS 9"; - case QSysInfo::MV_10_0: return "Mac OS X 10.0"; - case QSysInfo::MV_10_1: return "Mac OS X 10.1"; - case QSysInfo::MV_10_2: return "Mac OS X 10.2"; - case QSysInfo::MV_10_3: return "Mac OS X 10.3"; - case QSysInfo::MV_10_4: return "Mac OS X 10.4"; - case QSysInfo::MV_10_5: return "Mac OS X 10.5"; - - default: return "Unknown"; - } - #elif defined Q_WS_X11 - return "UNIX X11"; - #else - return "Unknown"; - #endif - } - - inline QString md5( const QByteArray& src ) - { - QByteArray const digest = QCryptographicHash::hash( src, QCryptographicHash::Md5 ); - return QString::fromLatin1( digest.toHex() ).rightJustified( 32, '0' ).toLower(); - } -} - -#ifdef Q_WS_MAC -inline QString lastfm::CFStringToQString( CFStringRef s ) -{ - return QString::fromUtf8( CFStringToUtf8( s ) ); -} -#endif -#endif //LASTFM_MISC_H diff --git a/thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt b/thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt deleted file mode 100644 index eae8397a8..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -include_directories(${LIBFFTW3_INCLUDE_DIRS}) -include_directories(${LIBSAMPLERATE_INCLUDE_DIRS}) -include_directories(${QT_INCLUDES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) - -link_directories(${LIBFFTW3_LIBRARY_DIRS}) -link_directories(${LIBSAMPLERATE_LIBRARY_DIRS}) - -set(SOURCES - Collection.cpp - Fingerprint.cpp - Sha256.cpp - fplib/Filter.cpp - fplib/FingerprintExtractor.cpp - fplib/OptFFT.cpp -) - -add_library(tomahawk_lastfm2_fingerprint SHARED - ${SOURCES} -) - -target_link_libraries(tomahawk_lastfm2_fingerprint - ${QT_LIBRARIES} - ${QT_QTSQL_LIBRARY} - ${LIBFFTW3_LIBRARY} - ${LIBSAMPLERATE_LIBRARY} - tomahawk_lastfm2 -) - -set_target_properties(tomahawk_lastfm2_fingerprint PROPERTIES COMPILE_FLAGS "-DLASTFM_FINGERPRINT_OHAI_QMAKE" ) diff --git a/thirdparty/liblastfm2/src/fingerprint/Collection.cpp b/thirdparty/liblastfm2/src/fingerprint/Collection.cpp deleted file mode 100644 index 214e264e2..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Collection.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "Collection.h" -#include "../core/misc.h" -#include -#include -#include -#include -#include -#include -#include - -static const int k_collectionDbVersion = 1; - -// Singleton instance needs to be initialised -Collection* Collection::s_instance = NULL; - - -Collection::Collection() -{ - m_db = QSqlDatabase::addDatabase( "QSQLITE", "collection" ); - m_db.setDatabaseName( lastfm::dir::runtimeData().filePath( "collection.db" ) ); - - if (!m_db.open()) { - qDebug() << m_db.lastError(); - return; - } - - if (!m_db.isValid()) { - qWarning() << "collection.db connection is not valid"; - return; - } - - if (!m_db.tables().contains( "files" )) - { - qDebug() << "Creating Collection database"; - - query( "CREATE TABLE artists (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "serverUid INTEGER," - "lcName TEXT NOT NULL," - "displayName TEXT NOT NULL );" ); - - query( "CREATE TABLE albums (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "serverUid INTEGER," - "lcName TEXT NOT NULL," - "displayName TEXT NOT NULL," - "primaryArtist INTEGER NOT NULL );" ); - - query( "CREATE UNIQUE INDEX album_names_idx ON albums ( primaryArtist, lcName );" ); - - query( "CREATE TABLE tracks (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "lcName TEXT NOT NULL," - "displayName TEXT NOT NULL," - "primaryArtist INTEGER NOT NULL," - "primaryAlbum INTEGER );" ); - - query( "CREATE UNIQUE INDEX track_names_idx ON tracks ( primaryArtist, lcName );" ); - - query( "CREATE TABLE files (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "uri TEXT NOT NULL," - "track INTEGER NOT NULL," - "bitrate INTEGER," - "samplerate INTEGER," - "duration INTEGER," - "filesize INTEGER," - "source INTEGER," - "modificationDate INTEGER," - "lastPlayDate INTEGER," - "playCounter INTEGER," - "mbId VARCHAR( 36 )," - "fpId INTEGER );" ); - - query( "CREATE UNIQUE INDEX files_uri_idx ON files ( uri );" ); - query( "CREATE INDEX files_track_idx ON files ( track );" ); - query( "CREATE INDEX files_fpId_idx ON files ( fpId );" ); - query( "CREATE INDEX files_source_idx ON files ( source );" ); - - query( "CREATE TABLE sources (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "name TEXT UNIQUE," - "available INTEGER," - "host TEXT," - "cost INTEGER );" ); - - query( "CREATE TABLE genres (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "name TEXT UNIQUE );" ); - - query( "CREATE TABLE labels (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "serverUid INTEGER UNIQUE," - "name TEXT );" ); - } - - int const v = version(); - if ( v < k_collectionDbVersion ) - { - qDebug() << "Upgrading Collection::db from" << v << "to" << k_collectionDbVersion; - - /********************************************** - * README!!!!!!! * - * Ensure you use v < x * - * Ensure you do upgrades in ascending order! * - **********************************************/ - - if ( v < 1 ) - { - // Norman discovered that he stored some fpId's wrong prior to 17th December 2007 - // So we have to wipe the fpIds for databases without the metadata table - // we didn't store version information before that, which was a bad decision wasn't it? - - // this will trigger refingerprinting of every track - query( "UPDATE files SET fpId = NULL;" ); - - query( "CREATE TABLE metadata (" - "key TEXT UNIQUE NOT NULL," - "value TEXT );" ); - - query( "INSERT INTO metadata (key, value) VALUES ('version', '1');" ); - } - - - // do last, update DB version number - query( "UPDATE metadata set key='version', value='" - + QString::number( k_collectionDbVersion ) + "';" ); - } -} - - -Collection& //static -Collection::instance() -{ - static QMutex mutex; - QMutexLocker locker( &mutex ); - - if ( !s_instance ) - { - s_instance = new Collection; - qAddPostRoutine(destroy); - } - - return *s_instance; -} - - -void //static -Collection::destroy() -{ - delete s_instance; - QSqlDatabase::removeDatabase( "collection" ); -} - - -int -Collection::version() const -{ - QSqlQuery sql( m_db ); - sql.exec( "SELECT value FROM metadata WHERE key='version';" ); - - if ( sql.next() ) - { - return sql.value( 0 ).toInt(); - } - - return 0; -} - - -bool -Collection::query( const QString& queryToken ) -{ - QSqlQuery query( m_db ); - query.exec( queryToken ); - - if ( query.lastError().isValid() ) - { - qDebug() << "SQL query failed:" << query.lastQuery() << endl - << "SQL error was:" << query.lastError().databaseText() << endl - << "SQL error type:" << query.lastError().type(); - - return false; - } - - return true; -} - - -QString -Collection::fileURI( const QString& filePath ) -{ - QString prefix( "file:/" ); - -#ifdef WIN32 - prefix = "file://"; -#endif - - return prefix + QFileInfo( filePath ).absoluteFilePath(); -} - - -QString -Collection::getFingerprintId( const QString& filePath ) -{ - QSqlQuery query( m_db ); - query.prepare( "SELECT fpId FROM files WHERE uri = :uri" ); - query.bindValue( ":uri", fileURI( filePath ) ); - - query.exec(); - if ( query.lastError().isValid() ) - { - qDebug() << "SQL query failed:" << query.lastQuery() << endl - << "SQL error was:" << query.lastError().databaseText() << endl - << "SQL error type:" << query.lastError().type(); - } - else if (query.next()) - return query.value( 0 ).toString(); - - return ""; -} - - -bool -Collection::setFingerprintId( const QString& filePath, QString fpId ) -{ - bool isNumeric; - int intFpId = fpId.toInt( &isNumeric ); - Q_ASSERT( isNumeric ); - - QSqlQuery query( m_db ); - query.prepare( "REPLACE INTO files ( uri, track, fpId ) VALUES ( :uri, 0, :fpId )" ); - query.bindValue( ":uri", fileURI( filePath ) ); - query.bindValue( ":fpId", intFpId ); - query.exec(); - - if ( query.lastError().isValid() ) - { - qDebug() << "SQL query failed:" << query.lastQuery() << endl - << "SQL error was:" << query.lastError().databaseText() << endl - << "SQL error type:" << query.lastError().type(); - - return false; - } - - return true; -} diff --git a/thirdparty/liblastfm2/src/fingerprint/Collection.h b/thirdparty/liblastfm2/src/fingerprint/Collection.h deleted file mode 100644 index 9a1f3bd17..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Collection.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -/** Class that we use to store fingerprints, basically - */ - -#ifndef COLLECTION_H -#define COLLECTION_H - -#include -#include - - -/** @author: */ -class Collection -{ -public: - static Collection& instance(); - - /** \brief Temp method: Gets a fingerprint id. Returns "" if none found. */ - QString getFingerprintId( const QString& filePath ); - - /** \brief Temp method: Sets a fingerprint id. */ - bool setFingerprintId( const QString& filePath, QString fpId ); - -private: - Collection(); - - /** the database version - * version 0: up until 1.4.1 - * version 1: from 1.4.2 */ - int version() const; - bool query( const QString& queryToken ); - QString fileURI( const QString& filePath ); - - static void destroy(); - - static Collection* s_instance; - QSqlDatabase m_db; -}; - -#endif // COLLECTION_H diff --git a/thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp b/thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp deleted file mode 100644 index f86d4bbaf..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/EXAMPLE.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include -#include -#include - -using namespace lastfm; - - -static void finish( QNetworkReply* reply ) -{ - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); -} - - -int main( int argc, char** argv ) -{ - QCoreApplication app( argc, argv ); - - // these fields are required - MutableTrack t; - t.setArtist( "Air" ); - t.setTitle( "Redhead Girl" ); - t.setAlbum( "Pocket Symphony" ); - t.setUrl( QUrl::fromLocalFile( "/Users/mxcl/Music/iTunes/iTunes Music/Air/Pocket Symphony/1-11 Redhead Girl.mp3") ); - - try - { - Fingerprint fp( t ); - - // we cache FingerprintIds in an sqlite3 db, as the generate() function - // is expensive - if (fp.id().isNull()) - { - // this generates the full fingerprint hash, which is about 20kB - fp.generate(); - - // this asks Last.fm for a FingerprintId - // the finish function is a Qt hack to allow syncronous HTTP - finish( fp.submit() ); - - // the decode step sets the FingerprintId - // the FingerprintId is required to obtain suggestions - // id will now be valid, or this function throws - fp.decode( reply ); - } - - finish( fp.id().getSuggestions() ); - - qDebug() << FingerprintId::getSuggestions( reply ); - } - catch (Fingerprint::Error e) - { - qWarning() << e; //TODO enum debug thing - } -} diff --git a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp b/thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp deleted file mode 100644 index b23805c7d..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "Fingerprint.h" -#include "FingerprintableSource.h" -#include "Collection.h" -#include "Sha256.h" -#include "fplib/FingerprintExtractor.h" -#include "../ws/ws.h" -#include -#include -#include -#include -#include -#include - -using lastfm::Track; - -static const uint k_bufferSize = 1024 * 8; -static const int k_minTrackDuration = 30; - - -lastfm::Fingerprint::Fingerprint( const Track& t ) - : m_track( t ) - , m_id( -1 ), m_duration( 0 ) - , m_complete( false ) -{ - QString id = Collection::instance().getFingerprintId( t.url().toLocalFile() ); - if (id.size()) { - bool b; - m_id = id.toInt( &b ); - if (!b) m_id = -1; - } -} - - -void -lastfm::Fingerprint::generate( FingerprintableSource* ms ) throw( Error ) -{ - //TODO throw if we can't get required metadata from the track object - -//TODO if (!QFileInfo( path ).isReadable()) -//TODO throw ReadError; - - int sampleRate, bitrate, numChannels; - - if ( !ms ) - throw ReadError; - - try - { - ms->init( m_track.url().toLocalFile() ); - ms->getInfo( m_duration, sampleRate, bitrate, numChannels ); - } - catch (std::exception& e) - { - qWarning() << e.what(); - throw HeadersError; - } - - - if (m_duration < k_minTrackDuration) - throw TrackTooShortError; - - ms->skipSilence(); - - bool fpDone = false; - fingerprint::FingerprintExtractor* extractor; - try - { - extractor = new fingerprint::FingerprintExtractor; - - if (m_complete) - { - extractor->initForFullSubmit( sampleRate, numChannels ); - } - else - { - extractor->initForQuery( sampleRate, numChannels, m_duration ); - - // Skippety skip for as long as the skipper sez (optimisation) - ms->skip( extractor->getToSkipMs() ); - float secsToSkip = extractor->getToSkipMs() / 1000.0f; - fpDone = extractor->process( 0, - (size_t) sampleRate * numChannels * secsToSkip, - false ); - } - } - catch (std::exception& e) - { - qWarning() << e.what(); - throw DecodeError; - } - - const size_t PCMBufSize = 131072; - short* pPCMBuffer = new short[PCMBufSize]; - - while (!fpDone) - { - size_t readData = ms->updateBuffer( pPCMBuffer, PCMBufSize ); - if (readData == 0) - break; - - try - { - fpDone = extractor->process( pPCMBuffer, readData, ms->eof() ); - } - catch ( const std::exception& e ) - { - qWarning() << e.what(); - delete ms; - delete[] pPCMBuffer; - throw InternalError; - } - } - - delete[] pPCMBuffer; - - if (!fpDone) - throw InternalError; - - // We succeeded - std::pair fpData = extractor->getFingerprint(); - - if (fpData.first == NULL || fpData.second == 0) - throw InternalError; - - // Make a deep copy before extractor gets deleted - m_data = QByteArray( fpData.first, fpData.second ); - delete extractor; -} - - -static QString sha256( const QString& path ) -{ - // no clue why this is static, there was no comment when I refactored it - // initially --mxcl - static uint8_t pBuffer[SHA_BUFFER_SIZE+7]; - - unsigned char hash[SHA256_HASH_SIZE]; - - { - QByteArray path8 = QFile::encodeName( path ); - std::ifstream inFile( path8.data(), std::ios::binary); - - SHA256Context sha256; - SHA256Init( &sha256 ); - - uint8_t* pMovableBuffer = pBuffer; - - // Ensure it is on a 64-bit boundary. - INTPTR offs; - if ((offs = reinterpret_cast(pBuffer) & 7L)) - pMovableBuffer += 8 - offs; - - unsigned int len; - - for (;;) - { - inFile.read( reinterpret_cast(pMovableBuffer), SHA_BUFFER_SIZE ); - len = inFile.gcount(); - - if (len == 0) - break; - - SHA256Update( &sha256, pMovableBuffer, len ); - } - - SHA256Final( &sha256, hash ); - } - - QString sha; - for (int i = 0; i < SHA256_HASH_SIZE; ++i) - { - QString hex = QString("%1").arg(uchar(hash[i]), 2, 16, - QChar('0')); - sha.append(hex); - } - - return sha; -} - - -static QByteArray number( uint n ) -{ - return n ? QByteArray::number( n ) : ""; -} - -QNetworkReply* -lastfm::Fingerprint::submit() const -{ - if (m_data.isEmpty()) - return 0; - - //Parameters understood by the server according to the MIR team: - //{ "trackid", "recordingid", "artist", "album", "track", "duration", - // "tracknum", "username", "sha256", "ip", "fpversion", "mbid", - // "filename", "genre", "year", "samplerate", "noupdate", "fulldump" } - - Track const t = m_track; - QString const path = t.url().toLocalFile(); - QFileInfo const fi( path ); - - #define e( x ) QUrl::toPercentEncoding( x ) - QUrl url( "http://www.last.fm/fingerprint/query/" ); - url.addEncodedQueryItem( "artist", e(t.artist()) ); - url.addEncodedQueryItem( "album", e(t.album()) ); - url.addEncodedQueryItem( "track", e(t.title()) ); - url.addEncodedQueryItem( "duration", number( m_duration > 0 ? m_duration : t.duration() ) ); - url.addEncodedQueryItem( "mbid", e(t.mbid()) ); - url.addEncodedQueryItem( "filename", e(fi.completeBaseName()) ); - url.addEncodedQueryItem( "fileextension", e(fi.completeSuffix()) ); - url.addEncodedQueryItem( "tracknum", number( t.trackNumber() ) ); - url.addEncodedQueryItem( "sha256", sha256( path ).toAscii() ); - url.addEncodedQueryItem( "time", number(QDateTime::currentDateTime().toTime_t()) ); - url.addEncodedQueryItem( "fpversion", QByteArray::number((int)fingerprint::FingerprintExtractor::getVersion()) ); - url.addEncodedQueryItem( "fulldump", m_complete ? "true" : "false" ); - url.addEncodedQueryItem( "noupdate", "false" ); - #undef e - - //FIXME: talk to mir about submitting fplibversion - - QNetworkRequest request( url ); - request.setHeader( QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=----------------------------8e61d618ca16" ); - - QByteArray bytes; - bytes += "------------------------------8e61d618ca16\r\n"; - bytes += "Content-Disposition: "; - bytes += "form-data; name=\"fpdata\""; - bytes += "\r\n\r\n"; - bytes += m_data; - bytes += "\r\n"; - bytes += "------------------------------8e61d618ca16--\r\n"; - - qDebug() << url; - qDebug() << "Fingerprint size:" << bytes.size() << "bytes"; - - return lastfm::nam()->post( request, bytes ); -} - - -void -lastfm::Fingerprint::decode( QNetworkReply* reply, bool* complete_fingerprint_requested ) throw( Error ) -{ - // The response data will consist of a number and a string. - // The number is the fpid and the string is either FOUND or NEW - // (or NOT FOUND when noupdate was used). NEW means we should - // schedule a full fingerprint. - // - // In the case of an error, there will be no initial number, just - // an error string. - - QString const response( reply->readAll() ); - QStringList const list = response.split( ' ' ); - - QString const fpid = list.value( 0 ); - QString const status = list.value( 1 ); - - if (response.isEmpty() || list.count() < 2 || response == "No response to client error") - goto bad_response; - if (list.count() != 2) - qWarning() << "Response looks bad but continuing anyway:" << response; - - { - // so variables go out of scope before jump to label - // otherwise compiler error on GCC 4.2 - bool b; - uint fpid_as_uint = fpid.toUInt( &b ); - if (!b) goto bad_response; - - Collection::instance().setFingerprintId( m_track.url().toLocalFile(), fpid ); - - if (complete_fingerprint_requested) - *complete_fingerprint_requested = (status == "NEW"); - - m_id = (int)fpid_as_uint; - return; - } - -bad_response: - qWarning() << "Response is bad:" << response; - throw BadResponseError; -} diff --git a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.h b/thirdparty/liblastfm2/src/fingerprint/Fingerprint.h deleted file mode 100644 index b793c4bb9..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Fingerprint.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_FINGERPRINT_H -#define LASTFM_FINGERPRINT_H - -#include -#include - - -namespace lastfm -{ - class LASTFM_FINGERPRINT_DLLEXPORT Fingerprint - { - lastfm::Track m_track; - QByteArray m_data; - int m_id; - int m_duration; - - protected: - bool m_complete; - - public: - /** represents a partial fingerprint of 20 seconds of music, this is - * considered 99.9999...9999% unique and so we use it for most stuff as - * it is much quicker than a complete fingerprint, still though, you - * should do the generate step in a thread. */ - Fingerprint( const lastfm::Track& ); - - /** if the id isNull(), then you'll need to do generate, submit and decode */ - FingerprintId id() const { return m_id; } - - /** The actual data that is the fingerprint, this is about 70kB or so, - * there isn't anything in it until you call generate. */ - QByteArray data() const { return m_data; } - - enum Error - { - ReadError = 0, - - /** failed to extract samplerate, bitrate, channels, duration etc */ - HeadersError, - - DecodeError, - - /** there is a minimum track duration for fingerprinting */ - TrackTooShortError, - - /** the fingerprint service went wrong, or we submitted bad data, - * or myabe the request failed, whatever, we couldn't parse the - * result */ - BadResponseError, - - /** sorry, liblastfm sucks, report bug with log! */ - InternalError - }; - - /** This is CPU intensive, do it in a thread in your GUI application */ - void generate( FingerprintableSource* ) throw( Error ); - - /** Submits the fingerprint data to Last.fm in order to get a FingerprintId - * back. You need to wait for the QNetworkReply to finish before you can - * pass it to decode clearly. */ - QNetworkReply* submit() const; - - /** Pass a finished reply from submit(), if the response is sound, id() - * will be valid. Otherwise we will throw. You always get a valid id - * or a throw. - */ - void decode( QNetworkReply*, bool* lastfm_needs_a_complete_fingerprint = 0 ) throw( Error ); - }; - - - class CompleteFingerprint : public Fingerprint - { - public: - CompleteFingerprint( const lastfm::Track& t ) : Fingerprint( t ) - { - m_complete = true; - } - }; -} - - -inline QDebug operator<<( QDebug d, lastfm::Fingerprint::Error e ) -{ - #define CASE(x) case lastfm::Fingerprint::x: return d << #x; - switch (e) - { - CASE(ReadError) - CASE(HeadersError) - CASE(DecodeError) - CASE(TrackTooShortError) - CASE(BadResponseError) - CASE(InternalError) - } - #undef CASE -} - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h b/thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h deleted file mode 100644 index 9954fd368..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/FingerprintableSource.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef LASTFM_FINGERPRINTABLE_SOURCE_H -#define LASTFM_FINGERPRINTABLE_SOURCE_H - -#include -#include - -namespace lastfm -{ - class LASTFM_FINGERPRINT_DLLEXPORT FingerprintableSource - { - public: - /** do all initialisation here and throw if there is problems */ - virtual void init( const QString& path ) = 0; - - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) = 0; - - /** put a chunk of PCM data in pBuffer, don't exceed size, return the - * number of bytes you put in the buffer */ - virtual int updateBuffer( signed short* buffer, size_t bufferSize ) = 0; - - virtual void skip( const int mSecs ) = 0; - virtual void skipSilence( double silenceThreshold = 0.0001 ) = 0; - - virtual bool eof() const = 0; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/Sha256.cpp b/thirdparty/liblastfm2/src/fingerprint/Sha256.cpp deleted file mode 100644 index 9be3c18ac..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Sha256.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/*- - * Copyright (c) 2001-2003 Allan Saddi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id: sha256.c 680 2003-07-25 21:57:49Z asaddi $ - */ - -/* - * Define WORDS_BIGENDIAN if compiling on a big-endian architecture. - * - * Define SHA256_TEST to test the implementation using the NIST's - * sample messages. The output should be: - * - * ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad - * 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1 - * cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0 - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /* HAVE_CONFIG_H */ - -#if HAVE_INTTYPES_H -# include -#else -# if HAVE_STDINT_H -# include -# endif -#endif - -#include - -#include "Sha256.h" - -#ifndef lint -static const char rcsid[] = - "$Id: sha256.c 680 2003-07-25 21:57:49Z asaddi $"; -#endif /* !lint */ - -#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) -#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) - -#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) -#define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22)) -#define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25)) -#define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3)) -#define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10)) - -#define DO_ROUND() { \ - t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++); \ - t2 = SIGMA0(a) + Maj(a, b, c); \ - h = g; \ - g = f; \ - f = e; \ - e = d + t1; \ - d = c; \ - c = b; \ - b = a; \ - a = t1 + t2; \ -} - -static const uint32_t K[64] = { - 0x428a2f98L, 0x71374491L, 0xb5c0fbcfL, 0xe9b5dba5L, - 0x3956c25bL, 0x59f111f1L, 0x923f82a4L, 0xab1c5ed5L, - 0xd807aa98L, 0x12835b01L, 0x243185beL, 0x550c7dc3L, - 0x72be5d74L, 0x80deb1feL, 0x9bdc06a7L, 0xc19bf174L, - 0xe49b69c1L, 0xefbe4786L, 0x0fc19dc6L, 0x240ca1ccL, - 0x2de92c6fL, 0x4a7484aaL, 0x5cb0a9dcL, 0x76f988daL, - 0x983e5152L, 0xa831c66dL, 0xb00327c8L, 0xbf597fc7L, - 0xc6e00bf3L, 0xd5a79147L, 0x06ca6351L, 0x14292967L, - 0x27b70a85L, 0x2e1b2138L, 0x4d2c6dfcL, 0x53380d13L, - 0x650a7354L, 0x766a0abbL, 0x81c2c92eL, 0x92722c85L, - 0xa2bfe8a1L, 0xa81a664bL, 0xc24b8b70L, 0xc76c51a3L, - 0xd192e819L, 0xd6990624L, 0xf40e3585L, 0x106aa070L, - 0x19a4c116L, 0x1e376c08L, 0x2748774cL, 0x34b0bcb5L, - 0x391c0cb3L, 0x4ed8aa4aL, 0x5b9cca4fL, 0x682e6ff3L, - 0x748f82eeL, 0x78a5636fL, 0x84c87814L, 0x8cc70208L, - 0x90befffaL, 0xa4506cebL, 0xbef9a3f7L, 0xc67178f2L -}; - -#ifndef RUNTIME_ENDIAN - -#ifdef WORDS_BIGENDIAN - -#define BYTESWAP(x) (x) -#define BYTESWAP64(x) (x) - -#else /* WORDS_BIGENDIAN */ - -#define BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \ - (ROTL((x), 8) & 0x00ff00ffL)) -#define BYTESWAP64(x) _byteswap64(x) - -static inline uint64_t _byteswap64(uint64_t x) -{ - uint32_t a = x >> 32; - uint32_t b = (uint32_t) x; - return ((uint64_t) BYTESWAP(b) << 32) | (uint64_t) BYTESWAP(a); -} - -#endif /* WORDS_BIGENDIAN */ - -#else /* !RUNTIME_ENDIAN */ - -#define BYTESWAP(x) _byteswap(sc->littleEndian, x) -#define BYTESWAP64(x) _byteswap64(sc->littleEndian, x) - -#define _BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | \ - (ROTL((x), 8) & 0x00ff00ffL)) -#define _BYTESWAP64(x) __byteswap64(x) - -static inline uint64_t __byteswap64(uint64_t x) -{ - uint32_t a = x >> 32; - uint32_t b = (uint32_t) x; - return ((uint64_t) _BYTESWAP(b) << 32) | (uint64_t) _BYTESWAP(a); -} - -static inline uint32_t _byteswap(int littleEndian, uint32_t x) -{ - if (!littleEndian) - return x; - else - return _BYTESWAP(x); -} - -static inline uint64_t _byteswap64(int littleEndian, uint64_t x) -{ - if (!littleEndian) - return x; - else - return _BYTESWAP64(x); -} - -static inline void setEndian(int *littleEndianp) -{ - union { - uint32_t w; - uint8_t b[4]; - } endian; - - endian.w = 1L; - *littleEndianp = endian.b[0] != 0; -} - -#endif /* !RUNTIME_ENDIAN */ - -static const uint8_t padding[64] = { - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -void -SHA256Init (SHA256Context *sc) -{ -#ifdef RUNTIME_ENDIAN - setEndian (&sc->littleEndian); -#endif /* RUNTIME_ENDIAN */ - - sc->totalLength = 0LL; - sc->hash[0] = 0x6a09e667L; - sc->hash[1] = 0xbb67ae85L; - sc->hash[2] = 0x3c6ef372L; - sc->hash[3] = 0xa54ff53aL; - sc->hash[4] = 0x510e527fL; - sc->hash[5] = 0x9b05688cL; - sc->hash[6] = 0x1f83d9abL; - sc->hash[7] = 0x5be0cd19L; - sc->bufferLength = 0L; -} - -static void -burnStack (int size) -{ - char buf[128]; - - memset (buf, 0, sizeof (buf)); - size -= sizeof (buf); - if (size > 0) - burnStack (size); -} - -static void -SHA256Guts (SHA256Context *sc, const uint32_t *cbuf) -{ - uint32_t buf[64]; - uint32_t *W, *W2, *W7, *W15, *W16; - uint32_t a, b, c, d, e, f, g, h; - uint32_t t1, t2; - const uint32_t *Kp; - int i; - - W = buf; - - for (i = 15; i >= 0; i--) { - *(W++) = BYTESWAP(*cbuf); - cbuf++; - } - - W16 = &buf[0]; - W15 = &buf[1]; - W7 = &buf[9]; - W2 = &buf[14]; - - for (i = 47; i >= 0; i--) { - *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++); - W2++; - W15++; - } - - a = sc->hash[0]; - b = sc->hash[1]; - c = sc->hash[2]; - d = sc->hash[3]; - e = sc->hash[4]; - f = sc->hash[5]; - g = sc->hash[6]; - h = sc->hash[7]; - - Kp = K; - W = buf; - -#ifndef SHA256_UNROLL -#define SHA256_UNROLL 1 -#endif /* !SHA256_UNROLL */ - -#if SHA256_UNROLL == 1 - for (i = 63; i >= 0; i--) - DO_ROUND(); -#elif SHA256_UNROLL == 2 - for (i = 31; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 4 - for (i = 15; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 8 - for (i = 7; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 16 - for (i = 3; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 32 - for (i = 1; i >= 0; i--) { - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - } -#elif SHA256_UNROLL == 64 - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); - DO_ROUND(); DO_ROUND(); DO_ROUND(); DO_ROUND(); -#else -#error "SHA256_UNROLL must be 1, 2, 4, 8, 16, 32, or 64!" -#endif - - sc->hash[0] += a; - sc->hash[1] += b; - sc->hash[2] += c; - sc->hash[3] += d; - sc->hash[4] += e; - sc->hash[5] += f; - sc->hash[6] += g; - sc->hash[7] += h; -} - -void -SHA256Update (SHA256Context *sc, const void *vdata, uint32_t len) -{ - const uint8_t *data = (const uint8_t*)vdata; - uint32_t bufferBytesLeft; - uint32_t bytesToCopy; - int needBurn = 0; - -#ifdef SHA256_FAST_COPY - if (sc->bufferLength) { - bufferBytesLeft = 64L - sc->bufferLength; - - bytesToCopy = bufferBytesLeft; - if (bytesToCopy > len) - bytesToCopy = len; - - memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); - - sc->totalLength += bytesToCopy * 8L; - - sc->bufferLength += bytesToCopy; - data += bytesToCopy; - len -= bytesToCopy; - - if (sc->bufferLength == 64L) { - SHA256Guts (sc, sc->buffer.words); - needBurn = 1; - sc->bufferLength = 0L; - } - } - - while (len > 63L) { - sc->totalLength += 512L; - - SHA256Guts (sc, data); - needBurn = 1; - - data += 64L; - len -= 64L; - } - - if (len) { - memcpy (&sc->buffer.bytes[sc->bufferLength], data, len); - - sc->totalLength += len * 8L; - - sc->bufferLength += len; - } -#else /* SHA256_FAST_COPY */ - while (len) { - bufferBytesLeft = 64L - sc->bufferLength; - - bytesToCopy = bufferBytesLeft; - if (bytesToCopy > len) - bytesToCopy = len; - - memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); - - sc->totalLength += bytesToCopy * 8L; - - sc->bufferLength += bytesToCopy; - data += bytesToCopy; - len -= bytesToCopy; - - if (sc->bufferLength == 64L) { - SHA256Guts (sc, sc->buffer.words); - needBurn = 1; - sc->bufferLength = 0L; - } - } -#endif /* SHA256_FAST_COPY */ - - if (needBurn) - burnStack (sizeof (uint32_t[74]) + sizeof (uint32_t *[6]) + sizeof (int)); -} - -void -SHA256Final (SHA256Context *sc, uint8_t hash[SHA256_HASH_SIZE]) -{ - uint32_t bytesToPad; - uint64_t lengthPad; - int i; - - bytesToPad = 120L - sc->bufferLength; - if (bytesToPad > 64L) - bytesToPad -= 64L; - - lengthPad = BYTESWAP64(sc->totalLength); - - SHA256Update (sc, padding, bytesToPad); - SHA256Update (sc, &lengthPad, 8L); - - if (hash) { - for (i = 0; i < SHA256_HASH_WORDS; i++) { -#ifdef SHA256_FAST_COPY - *((uint32_t *) hash) = BYTESWAP(sc->hash[i]); -#else /* SHA256_FAST_COPY */ - hash[0] = (uint8_t) (sc->hash[i] >> 24); - hash[1] = (uint8_t) (sc->hash[i] >> 16); - hash[2] = (uint8_t) (sc->hash[i] >> 8); - hash[3] = (uint8_t) sc->hash[i]; -#endif /* SHA256_FAST_COPY */ - hash += 4; - } - } -} - -#ifdef SHA256_TEST - -#include -#include - -int -main (int argc, char *argv[]) -{ - SHA256Context foo; - uint8_t hash[SHA256_HASH_SIZE]; - char buf[1000]; - int i; - - SHA256Init (&foo); - SHA256Update (&foo, "abc", 3); - SHA256Final (&foo, hash); - - for (i = 0; i < SHA256_HASH_SIZE;) { - printf ("%02x", hash[i++]); - if (!(i % 4)) - printf (" "); - } - printf ("\n"); - - SHA256Init (&foo); - SHA256Update (&foo, - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - 56); - SHA256Final (&foo, hash); - - for (i = 0; i < SHA256_HASH_SIZE;) { - printf ("%02x", hash[i++]); - if (!(i % 4)) - printf (" "); - } - printf ("\n"); - - SHA256Init (&foo); - memset (buf, 'a', sizeof (buf)); - for (i = 0; i < 1000; i++) - SHA256Update (&foo, buf, sizeof (buf)); - SHA256Final (&foo, hash); - - for (i = 0; i < SHA256_HASH_SIZE;) { - printf ("%02x", hash[i++]); - if (!(i % 4)) - printf (" "); - } - printf ("\n"); - - exit (0); -} - -#endif /* SHA256_TEST */ diff --git a/thirdparty/liblastfm2/src/fingerprint/Sha256.h b/thirdparty/liblastfm2/src/fingerprint/Sha256.h deleted file mode 100644 index 433c8f9a6..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/Sha256.h +++ /dev/null @@ -1,180 +0,0 @@ -/*- - * Copyright (c) 2001-2003 Allan Saddi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id: sha256.h 348 2003-02-23 22:12:06Z asaddi $ - */ -// -/////////// EXAMPLE ///////////////////////////////// -// -// SHA256Context sha256; -// SHA256Init (&sha256); -// -// uint8_t* pBuffer = new uint8_t[SHA_BUFFER_SIZE + 7]; -// // Ensure it is on a 64-bit boundary. -// INTPTR offs; -// if ((offs = reinterpret_cast(pBuffer) & 7L)) -// pBuffer += 8 - offs; -// -// unsigned int len; -// -// ifstream inFile("test.txt", ios::binary); -// -// for (;;) -// { -// inFile.read( reinterpret_cast(pBuffer), SHA_BUFFER_SIZE ); -// len = inFile.gcount(); -// -// if ( len == 0) -// break; -// -// SHA256Update (&sha256, pBuffer, len); -// } -// -// uint8_t hash[SHA256_HASH_SIZE]; -// SHA256Final (&sha256, hash); -// -// cout << "Hash: "; -// for (int i = 0; i < SHA256_HASH_SIZE; ++i) -// printf ("%02x", hash[i]); -// cout << endl; - - -#ifndef _SHA256_H -#define _SHA256_H - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_INTTYPES_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_STDINT_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strerror' function. */ -#ifndef WIN32 -#define HAVE_STRERROR 1 -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_SYS_TYPES_H 1 -#endif - -/* Define to 1 if you have the header file. */ -#ifndef WIN32 -#define HAVE_UNISTD_H 1 -#endif - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define as `__inline' if that's what the C compiler calls it, or to nothing - if it is not supported. */ -#ifdef WIN32 -#define inline __inline -#endif - -/* Define to `unsigned' if does not define. */ -/* #undef size_t */ - -#ifdef WIN32 -#define uint64_t unsigned __int64 -#define uint32_t unsigned int -#define uint8_t unsigned char -#endif // WIN32 - -#ifdef WIN32 -#define INTPTR intptr_t -#else -#define INTPTR long -#endif - -#define SHA_BUFFER_SIZE 65536 - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - - -#if HAVE_INTTYPES_H -# include -#else -# if HAVE_STDINT_H -# include -# endif -#endif - -#define SHA256_HASH_SIZE 32 - -/* Hash size in 32-bit words */ -#define SHA256_HASH_WORDS 8 - -struct _SHA256Context { - uint64_t totalLength; - uint32_t hash[SHA256_HASH_WORDS]; - uint32_t bufferLength; - union { - uint32_t words[16]; - uint8_t bytes[64]; - } buffer; -#ifdef RUNTIME_ENDIAN - int littleEndian; -#endif /* RUNTIME_ENDIAN */ -}; - -typedef struct _SHA256Context SHA256Context; - -#ifdef __cplusplus -extern "C" { -#endif - -void SHA256Init (SHA256Context *sc); -void SHA256Update (SHA256Context *sc, const void *data, uint32_t len); -void SHA256Final (SHA256Context *sc, uint8_t hash[SHA256_HASH_SIZE]); - -#ifdef __cplusplus -} -#endif - -#endif /* !_SHA256_H */ diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp deleted file mode 100644 index 77bacd343..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.cpp +++ /dev/null @@ -1,953 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - Portions Copyright 2003-2005 M. Bakker, Nero AG, http://www.nero.com - - Adapted from main.c found in the FAAD2 source tarball. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "AacSource.h" -#include "AacSource_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -//////////////////////////////////////////////////////////////////////// -// -// AAC_File -// -//////////////////////////////////////////////////////////////////////// -AAC_File::AAC_File(const QString& fileName, int headerType) - : m_fileName(fileName) - , m_inBuf(NULL) - , m_inBufSize(0) - , m_decoder(0) - , m_overflow(static_cast(malloc( sizeof(unsigned char) * 1024 ))) - , m_overflowSize(0) - , m_header(headerType) -{ -} - - -AAC_File::~AAC_File() -{ - // common - if ( m_decoder ) - { - NeAACDecClose( m_decoder ); - m_decoder = NULL; - } - if ( m_inBuf ) - { - free( m_inBuf ); - m_inBufSize = 0; - m_inBuf = NULL; - } - if ( m_overflow ) - { - free( m_overflow ); - m_overflowSize = 0; - m_overflow = NULL; - } -} - - - -//////////////////////////////////////////////////////////////////////// -// -// AAC with ADTS or ADIF headers -// -//////////////////////////////////////////////////////////////////////// - - -#define MAX_CHANNELS 6 // Output will get mixed down to 2 channels -#define ADTS_HEADER_SIZE 8 - -static int adts_sample_rates[] = -{ - 96000, - 88200, - 64000, - 48000, - 44100, - 32000, - 24000, - 22050, - 16000, - 12000, - 11025, - 8000, - 7350, - 0, - 0, - 0 -}; - -AAC_ADTS_File::AAC_ADTS_File( const QString& fileName, int headerType ) : AAC_File(fileName, headerType) - , m_file( NULL ) - , m_adifSamplerate( 0 ) - , m_adifChannels( 0 ) -{ -} - - -AAC_ADTS_File::~AAC_ADTS_File() -{ - if ( m_file ) - { - fclose( m_file ); - } -} - - -void AAC_ADTS_File::fillBuffer( FILE*& fp, unsigned char*& buf, size_t& bufSize, const size_t bytesConsumed ) -{ - size_t bread; - - if ( bytesConsumed > 0 ) - { - if ( bufSize ) - memmove( (void*)buf, (void*)(buf + bytesConsumed), bufSize*sizeof(unsigned char) ); - - bread = fread( (void*)(buf + bufSize), 1, bytesConsumed, fp ); - bufSize += bread; - - if ( bufSize > 3 ) - { - if ( memcmp( buf, "TAG", 3 ) == 0 ) - bufSize = 0; - } - if ( bufSize > 11 ) - { - if ( memcmp( buf, "LYRICSBEGIN", 11 ) == 0 ) - bufSize = 0; - } - if ( bufSize > 8 ) - { - if ( memcmp( buf, "APETAGEX", 8 ) == 0 ) - bufSize = 0; - } - } -} - - -void AAC_ADTS_File::parse( FILE*& fp, unsigned char*& buf, size_t& bufSize, int &bitrate, double &length ) -{ - unsigned int frames, frame_length = 0; - int t_framelength = 0; - int samplerate = 0; - double frames_per_sec, bytes_per_frame; - - // Read all frames to ensure correct time and bitrate - for ( frames = 0; /* */; frames++ ) - { - fillBuffer( fp, buf, bufSize, frame_length ); - - if ( bufSize > 7 ) - { - /* check syncword */ - if ( !( (buf[0] == 0xFF) && ((buf[1] & 0xF6) == 0xF0) ) ) - break; - - if ( frames == 0 ) - samplerate = adts_sample_rates[ (buf[2] & 0x3c) >> 2 ]; - - frame_length = ( ((buf[3] & 0x3) << 11) - | ((buf[4]) << 3) - | (buf[5] >> 5) ); - - t_framelength += frame_length - ADTS_HEADER_SIZE; - - if ( frame_length > bufSize ) - break; - - bufSize -= frame_length; - } - else - { - break; - } - } - - frames_per_sec = samplerate / 1024.0; - - if ( frames != 0 ) - bytes_per_frame = t_framelength / frames; - else - bytes_per_frame = 0; - - bitrate = static_cast(8 * bytes_per_frame * frames_per_sec + 0.5); - - if ( frames_per_sec != 0 ) - length = frames / frames_per_sec; - else - length = 1; -} - - -int32_t AAC_ADTS_File::commonSetup( FILE*& fp, NeAACDecHandle& decoder, unsigned char*& buf, size_t& bufSize, uint32_t& samplerate, uint8_t& channels ) -{ - samplerate = 0; - channels = 0; - - fp = fopen(QFile::encodeName(m_fileName), "rb" ); - if( !fp ) - { - std::cerr << "ERROR: Failed to open " << strerror( errno ) << std::endl; - return -1; - } - - if ( !(buf = static_cast( malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS)) ) ) - { - std::cerr << "Memory allocation error" << std::endl; - fclose ( fp ); - return -1; - } - - memset( buf, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS ); - - bufSize = fread( buf, 1, FAAD_MIN_STREAMSIZE * MAX_CHANNELS, fp ); - - int tagsize = 0; - if ( !memcmp( buf, "ID3", 3 ) ) - { - /* high bit is not used */ - tagsize = (buf[6] << 21) | (buf[7] << 14) | - (buf[8] << 7) | (buf[9] << 0); - - tagsize += 10; - bufSize -= tagsize; - fillBuffer( fp, buf, bufSize, tagsize ); - } - - decoder = NeAACDecOpen(); - - /* Set configuration */ - NeAACDecConfigurationPtr config; - config = NeAACDecGetCurrentConfiguration(decoder); - config->outputFormat = FAAD_FMT_16BIT; - config->downMatrix = 1; // Turn 5.1 channels into 2 - NeAACDecSetConfiguration( decoder, config); - - int32_t initval = 0; - if ((initval = NeAACDecInit(decoder, buf, - FAAD_MIN_STREAMSIZE*MAX_CHANNELS, &samplerate, &channels)) < 0) - { - std::cerr << "Error: could not set up AAC decoder" << std::endl; - if ( buf ) - free( buf ); - buf = NULL; - NeAACDecClose( decoder ); - decoder = NULL; - fclose( fp ); - fp = NULL; - } - return initval; -} - - -bool AAC_ADTS_File::init() -{ - uint32_t initSamplerate = 0; - uint8_t initChannels = 0; - int32_t initval = commonSetup( m_file, m_decoder, m_inBuf, m_inBufSize, initSamplerate, initChannels ); - - if ( initval >= 0 ) - { - m_inBufSize -= initval; - fillBuffer( m_file, m_inBuf, m_inBufSize, initval ); - - // These two only needed for skipping AAC ADIF files - m_adifSamplerate = initSamplerate; - m_adifChannels = initChannels; - - return true; - } - - throw std::runtime_error( "ERROR: Could not initialize AAC file reader!" ); - return false; -} - - -/*QString AAC_ADTS_File::getMbid() -{ - char out[MBID_BUFFER_SIZE]; - int const r = getMP3_MBID(QFile::encodeName(m_fileName), out); - if ( r == 0 ) - return QString::fromLatin1( out ); - return QString(); -}*/ - -void AAC_ADTS_File::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - long fileread; - uint32_t initSamplerate; - uint8_t initChannels; - double initLength = 0; - unsigned char *tempBuf = NULL; - size_t tempBufSize; - FILE *fp = NULL; - NeAACDecHandle decoder = NULL; - commonSetup( fp, decoder, tempBuf, tempBufSize, initSamplerate, initChannels ); - - long origpos = ftell( fp ); - fseek( fp, 0, SEEK_END ); - fileread = ftell( fp ); - fseek( fp, origpos, SEEK_SET ); - - if ( (tempBuf[0] == 0xFF) && ((tempBuf[1] & 0xF6) == 0xF0) ) - { - parse( fp, tempBuf, tempBufSize, bitrate, initLength ); - } - else if (memcmp(tempBuf, "ADIF", 4) == 0) - { - int skip_size = (tempBuf[4] & 0x80) ? 9 : 0; - bitrate = ((tempBuf[4 + skip_size] & 0x0F)<<19) | - (tempBuf[5 + skip_size]<<11) | - (tempBuf[6 + skip_size]<<3) | - (tempBuf[7 + skip_size] & 0xE0); - - if ( fileread != 0) - { - initLength = static_cast(fileread) * 8 / bitrate + 0.5; - } - } - - lengthSecs = static_cast(initLength); - nchannels = initChannels; - samplerate = initSamplerate; - - if ( decoder ) - NeAACDecClose( decoder ); - if ( fp ) - fclose( fp ); - if ( tempBuf ) - free( tempBuf ); -} - - -void AAC_ADTS_File::skip( const int mSecs ) -{ - if ( m_header == AAC_ADTS ) - { - // As AAC is VBR we need to check all ADTS headers to enable seeking... - // There is no other solution - unsigned char header[8]; - unsigned int frameCount, frameLength; - double seconds = 0; - - // We need to find the ATDS syncword so rewind to the beginning - // of the unprocessed data. - if ( m_inBufSize > 0 ) - { - fseek ( m_file, -m_inBufSize, SEEK_CUR ); - m_inBufSize = 0; - } - - for( frameCount = 1; seconds * 1000 < mSecs; frameCount++ ) - { - if ( fread( header, 1, ADTS_HEADER_SIZE, m_file ) != ADTS_HEADER_SIZE ) - { - break; - } - if ( !strncmp( (char*)header, "ID3", 3 ) ) - { - // high bit is not used - unsigned char rest[2]; - fread( rest, 1, 2, m_file ); - int tagsize = (header[6] << 21) | (header[7] << 14) | - (rest[0] << 7) | (rest[1] << 0); - - fseek( m_file, tagsize, SEEK_CUR ); - fread( header, 1, ADTS_HEADER_SIZE, m_file ); - } - if ( !((header[0] == 0xFF) && ((header[1] & 0xF6) == 0xF0)) ) - { - std::cerr << "Error: Bad frame header; file may be corrupt!" << std::endl; - break; - } - - int samplerate = adts_sample_rates[ (header[2] & 0x3c) >> 2 ]; - frameLength = ( ( header[3] & 0x3 ) << 11 ) - | ( header[4] << 3 ) - | ( header[5] >> 5 ); - - if ( samplerate > 0 ) - seconds += 1024.0 / samplerate; - else - { - std::cerr << "Error: Bad frame header; file may be corrupt!" << std::endl; - break; - } - - if ( fseek( m_file, frameLength - ADTS_HEADER_SIZE, SEEK_CUR ) == -1 ) - break; - } - m_inBufSize = fread( m_inBuf, 1, FAAD_MIN_STREAMSIZE * MAX_CHANNELS, m_file ); - } - else if ( m_header == AAC_ADIF ) - { - // AAC ADIF is even worse. There's only the one header at the - // beginning of the file. If you want to skip forward, you have to - // decode block by block and check how far along you are. Lovely, eh? - - unsigned long totalSamples = 0; - void *sampleBuffer = NULL; - - do - { - NeAACDecFrameInfo frameInfo; - sampleBuffer = NeAACDecDecode(m_decoder, &frameInfo, m_inBuf, static_cast(m_inBufSize) ); - totalSamples += frameInfo.samples; - if ( frameInfo.bytesconsumed > 0 ) - { - m_inBufSize -= frameInfo.bytesconsumed; - fillBuffer( m_file, m_inBuf, m_inBufSize, frameInfo.bytesconsumed ); - } - if ( totalSamples >= ( mSecs * m_adifSamplerate * m_adifChannels / 1000 ) ) - break; - } while ( sampleBuffer != NULL ); - } -} - - -void AAC_ADTS_File::postDecode(unsigned long bytesConsumed) -{ - m_inBufSize -= bytesConsumed; - fillBuffer( m_file, m_inBuf, m_inBufSize, bytesConsumed ); -} - - -//////////////////////////////////////////////////////////////////////// -// -// AAC in an MP4 wrapper -// -//////////////////////////////////////////////////////////////////////// - - -uint32_t read_callback( void *user_data, void *buffer, uint32_t length ) -{ - return static_cast(fread( buffer, 1, length, static_cast(user_data) )); -} - - -uint32_t seek_callback( void *user_data, uint64_t position ) -{ - return fseek( static_cast(user_data), static_cast(position), SEEK_SET ); -} - -AAC_MP4_File::AAC_MP4_File( const QString& fileName, int headerType ) : AAC_File(fileName, headerType) - , m_mp4AudioTrack( -1 ) - , m_mp4SampleId( 0 ) - , m_mp4File ( NULL ) - , m_mp4cb ( NULL ) -{ -} - -int32_t AAC_MP4_File::readSample() -{ - unsigned int bsize; - int32_t rc = mp4ff_read_sample( m_mp4File, m_mp4AudioTrack, m_mp4SampleId, &m_inBuf, &bsize ); - m_inBufSize = bsize; - // Not necessarily an error. Could just mean end of file. - //if ( rc == 0 ) - // std::cerr << "Reading samples failed." << std::endl; - return rc; -} - - -int32_t AAC_MP4_File::getTrack( const mp4ff_t *f ) -{ - // find AAC track - int32_t numTracks = mp4ff_total_tracks( f ); - - for ( int32_t i = 0; i < numTracks; i++ ) - { - unsigned char *buff = NULL; - unsigned int buff_size = 0; - mp4AudioSpecificConfig mp4ASC; - - mp4ff_get_decoder_config( f, i, &buff, &buff_size ); - - if ( buff ) - { - int8_t rc = NeAACDecAudioSpecificConfig( buff, buff_size, &mp4ASC ); - free( buff ); - - if ( rc < 0 ) - continue; - return i; - } - } - - // can't decode this, probably DRM - return -1; -} - - -bool AAC_MP4_File::commonSetup( NeAACDecHandle& decoder, mp4ff_callback_t*& cb, FILE*& fp, mp4ff_t*& mp4, int32_t& audioTrack ) -{ - fp = fopen(QFile::encodeName(m_fileName), "rb"); - if ( !fp ) - { - throw std::runtime_error( "Error: failed to open AAC file!" ); - return false; - } - - decoder = NeAACDecOpen(); - - // Set configuration - NeAACDecConfigurationPtr config; - config = NeAACDecGetCurrentConfiguration( decoder ); - config->outputFormat = FAAD_FMT_16BIT; - config->downMatrix = 1; // Turn 5.1 channels into 2 - NeAACDecSetConfiguration( decoder, config ); - - // initialise the callback structure - cb = static_cast( malloc( sizeof(mp4ff_callback_t) ) ); - - cb->read = read_callback; - cb->seek = seek_callback; - cb->user_data = fp; - - mp4 = mp4ff_open_read( cb ); - - if ( !mp4 ) - { - // unable to open file - free( cb ); - cb = NULL; - NeAACDecClose( decoder ); - decoder = NULL; - fclose( fp ); - fp = NULL; - throw std::runtime_error( "Error: failed to set up AAC decoder!" ); - return false; - } - - if ( ( audioTrack = getTrack( mp4 )) < 0 ) - { - free( cb ); - cb = NULL; - NeAACDecClose( decoder ); - decoder = NULL; - fclose( fp ); - fp = NULL; - mp4ff_close( mp4 ); - mp4 = NULL; - audioTrack = 0; - throw std::runtime_error( "Error: Unable to find an audio track. Is the file DRM protected?" ); - return false; - } - return true; -} - - -/*QString AAC_MP4_File::getMbid() -{ - int j = mp4ff_meta_get_num_items( m_mp4File ); - if ( j > 0 ) - { - int k; - for ( k = 0; k < j; k++ ) - { - char *tag = NULL, *item = NULL; - if ( mp4ff_meta_get_by_index( m_mp4File, k, &item, &tag ) ) - { - if ( item != NULL && tag != NULL ) - { - QString key(item); - if ( key.toLower() == "musicbrainz track id" ) - { - QString ret(tag); - free( item ); - free( tag ); - return ret; - } - free( item ); - free( tag ); - } - } - } - } - return QString(); -}*/ - - -void AAC_MP4_File::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - FILE* fp = NULL; - mp4ff_callback_t *cb = NULL; - NeAACDecHandle decoder = NULL; - mp4ff_t* mp4 = NULL; - int32_t audioTrack; - - bool success = commonSetup( decoder, cb, fp, mp4, audioTrack ); - - if ( success ) - { - // get basic file info - mp4AudioSpecificConfig mp4ASC; - unsigned char* buffer = NULL; - unsigned int buffer_size = 0; - double f = 1024.0; - unsigned int framesize = 1024; - - int32_t samples = mp4ff_num_samples( mp4, audioTrack ); - - if ( buffer ) - { - if ( NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0 ) - { - if ( mp4ASC.frameLengthFlag == 1 ) - framesize = 960; - if ( mp4ASC.sbr_present_flag == 1 ) - framesize *= 2; - if ( mp4ASC.sbr_present_flag == 1 ) - f = f * 2.0; - } - free( buffer ); - } - - samplerate = mp4ff_get_sample_rate( mp4, audioTrack ); - if ( samplerate > 0 ) - lengthSecs = static_cast(samples * f / samplerate + 0.5); - bitrate = mp4ff_get_avg_bitrate( mp4, audioTrack ); - nchannels = mp4ff_get_channel_count( mp4, audioTrack ); - - mp4ff_close( mp4 ); - NeAACDecClose( decoder ); - free( cb ); - fclose( fp ); - } -} - - -bool AAC_MP4_File::init() -{ - FILE* fp = NULL; - - bool success = commonSetup( m_decoder, m_mp4cb, fp, m_mp4File, m_mp4AudioTrack ); - if ( !success ) - return false; - - unsigned char* buffer = NULL; - unsigned int buffer_size = 0; - uint32_t samplerate; - uint8_t channels; - - mp4ff_get_decoder_config( m_mp4File, m_mp4AudioTrack, &buffer, &buffer_size ); - - if( NeAACDecInit2( m_decoder, buffer, buffer_size, &samplerate, &channels) < 0 ) - { - // If some error initializing occured, skip the file - if ( fp ) - fclose( fp ); - throw std::runtime_error( "Error: unable to initialize AAC decoder library!" ); - return false; - } - - if ( buffer ) - free( buffer ); - - return true; -} - - -void AAC_MP4_File::postDecode(unsigned long) -{ - free( m_inBuf ); - m_inBuf = NULL; - m_mp4SampleId++; -} - -void AAC_MP4_File::skip( const int mSecs ) -{ - double dur = 0.0; - int f = 1; - unsigned char *buff = NULL; - unsigned int buff_size = 0; - uint32_t totalSamples = mp4ff_num_samples( m_mp4File, m_mp4AudioTrack ); - mp4AudioSpecificConfig mp4ASC; - - mp4ff_get_decoder_config( m_mp4File, m_mp4AudioTrack, &buff, &buff_size ); - - if ( buff ) - { - int8_t rc = NeAACDecAudioSpecificConfig( buff, buff_size, &mp4ASC ); - free( buff ); - if ( rc >= 0 && mp4ASC.sbr_present_flag == 1 ) - f = 2; - - // I think the f multiplier is needed here. - while ( dur * 1000.0 * f / static_cast(mp4ASC.samplingFrequency) < mSecs && m_mp4SampleId < totalSamples ) - { - dur += mp4ff_get_sample_duration( m_mp4File, m_mp4AudioTrack, m_mp4SampleId ); - m_mp4SampleId++; - } - } - else - std::cerr << "Error: could not skip " << mSecs << " milliseconds" << std::endl; -} - - -AAC_MP4_File::~AAC_MP4_File() -{ - if ( m_mp4File ) - mp4ff_close( m_mp4File ); - if ( m_mp4cb ) - { - free( m_mp4cb ); - } -} - - -//////////////////////////////////////////////////////////////////////// -// -// AacSource -// -//////////////////////////////////////////////////////////////////////// - -AacSource::AacSource() - : m_eof( false ) - , m_aacFile( NULL ) -{} - - -AacSource::~AacSource() -{ - delete m_aacFile; -} - - -int AacSource::checkHeader() -{ - FILE *fp = NULL; - unsigned char header[10]; - - // check for mp4 file - fp = fopen(QFile::encodeName(m_fileName), "rb"); - if ( !fp ) - { - std::cerr << "Error: failed to open " << strerror( errno ) << std::endl; - return AAC_File::AAC_UNKNOWN; - } - - fread( header, 1, 10, fp ); - - // MP4 headers - if ( !memcmp( &header[4], "ftyp", 4 ) ) - { - fclose( fp ); - return AAC_File::AAC_MP4; - } - - // Skip id3 tags - int tagsize = 0; - if ( !memcmp( header, "ID3", 3 ) ) - { - /* high bit is not used */ - tagsize = (header[6] << 21) | (header[7] << 14) | - (header[8] << 7) | (header[9] << 0); - - tagsize += 10; - fseek( fp, tagsize, SEEK_SET ); - fread( header, 1, 10, fp ); - } - - // Check for ADTS OR ADIF headers - if ( (header[0] == 0xFF) && ((header[1] & 0xF6) == 0xF0) ) - { - fclose( fp ); - return AAC_File::AAC_ADTS; - } - else if (memcmp(header, "ADIF", 4) == 0) - { - fclose( fp ); - return AAC_File::AAC_ADIF; - } - - fclose( fp ); - return AAC_File::AAC_UNKNOWN; -} - - -void AacSource::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - // get the header plus some other stuff.. - - m_aacFile->getInfo( lengthSecs, samplerate, bitrate, nchannels ); -} - - -void AacSource::init(const QString& fileName) -{ - m_fileName = fileName; - - int headerType = checkHeader(); - if ( headerType != AAC_File::AAC_UNKNOWN ) - { - if ( headerType == AAC_File::AAC_MP4 ) - m_aacFile = new AAC_MP4_File(m_fileName, headerType); - else - m_aacFile = new AAC_ADTS_File( m_fileName, headerType ); - } - - if ( m_aacFile ) - m_aacFile->init(); - else - throw std::runtime_error( "ERROR: No suitable AAC decoder found!" ); -} - - -/*QString AacSource::getMbid() -{ - QString mbid = m_aacFile->getMbid(); - return mbid; -}*/ - - -void AacSource::skip( const int mSecs ) -{ - if ( mSecs < 0 || !m_aacFile->m_decoder ) - return; - - m_aacFile->skip( mSecs ); -} - - -void AacSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - if ( !m_aacFile->m_decoder ) - return; - - silenceThreshold *= static_cast( std::numeric_limits::max() ); - - for (;;) - { - if ( m_aacFile->m_header == AAC_File::AAC_MP4 ) - { - if ( !static_cast(m_aacFile)->readSample() ) - break; - } - NeAACDecFrameInfo frameInfo; - - void* sampleBuffer = NeAACDecDecode(m_aacFile->m_decoder, &frameInfo, m_aacFile->m_inBuf, static_cast(m_aacFile->m_inBufSize) ); - - m_aacFile->postDecode( frameInfo.bytesconsumed ); - - if ( frameInfo.error > 0 ) - { - break; - } - else if ( frameInfo.samples > 0 ) - { - double sum = 0; - int16_t *buf = static_cast(sampleBuffer); - switch ( frameInfo.channels ) - { - case 1: - for (size_t j = 0; j < frameInfo.samples; ++j) - sum += abs( buf[j] ); - break; - case 2: - for (size_t j = 0; j < frameInfo.samples; j+=2) - sum += abs( (buf[j] >> 1) + (buf[j+1] >> 1) ); - break; - } - if ( (sum >= silenceThreshold * static_cast(frameInfo.samples/frameInfo.channels) ) ) - break; - } - } -} - - -int AacSource::updateBuffer( signed short *pBuffer, size_t bufferSize ) -{ - size_t nwrit = 0; //number of samples written to the output buffer - - if ( m_aacFile->m_overflowSize > 0 ) - { - size_t samples_to_use = bufferSize < m_aacFile->m_overflowSize ? bufferSize : m_aacFile->m_overflowSize; - memcpy( pBuffer, m_aacFile->m_overflow, samples_to_use * sizeof(signed short) ); - nwrit += samples_to_use; - m_aacFile->m_overflowSize -= samples_to_use; - memmove( (void*)(m_aacFile->m_overflow), (void*)(m_aacFile->m_overflow + samples_to_use*sizeof(signed short)), samples_to_use*sizeof(signed short) ); - } - - if ( !m_aacFile->m_decoder ) - return 0; - - for (;;) - { - signed short* pBufferIt = pBuffer + nwrit; - void* sampleBuffer; - - assert( nwrit <= bufferSize ); - - if ( m_aacFile->m_header == AAC_File::AAC_MP4 ) - { - if ( !static_cast(m_aacFile)->readSample() ) - { - m_eof = true; - return static_cast(nwrit); - } - } - NeAACDecFrameInfo frameInfo; - - sampleBuffer = NeAACDecDecode(m_aacFile->m_decoder, &frameInfo, m_aacFile->m_inBuf, static_cast(m_aacFile->m_inBufSize) ); - size_t samples_to_use = (bufferSize - nwrit) < frameInfo.samples ? bufferSize-nwrit : frameInfo.samples; - - if ( samples_to_use > 0 && sampleBuffer != NULL ) - { - memcpy( pBufferIt, sampleBuffer, samples_to_use * sizeof(signed short) ); - nwrit += samples_to_use; - } - - if ( samples_to_use < frameInfo.samples ) - { - m_aacFile->m_overflow = static_cast(realloc( m_aacFile->m_overflow, (frameInfo.samples - samples_to_use) * sizeof(signed short) ) ); - memcpy( m_aacFile->m_overflow, static_cast(sampleBuffer) + samples_to_use, (frameInfo.samples - samples_to_use) * sizeof(signed short) ); - m_aacFile->m_overflowSize = frameInfo.samples - samples_to_use; - } - - m_aacFile->postDecode( frameInfo.bytesconsumed ); - - if ( sampleBuffer == NULL ) - { - m_eof = true; - break; - } - - if ( frameInfo.error > 0 ) - { - std::cerr << "Error: " << NeAACDecGetErrorMessage(frameInfo.error) << std::endl; - break; - } - - if ( nwrit == bufferSize ) - break; - } - - return static_cast(nwrit); -} diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h deleted file mode 100644 index 0fff6f585..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __AAC_SOURCE_H__ -#define __AAC_SOURCE_H__ - -#include - -class AacSource : public lastfm::FingerprintableSource -{ -public: - AacSource(); - ~AacSource(); - - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - virtual bool eof() const { return m_eof; } - -private: - int checkHeader(); - QString m_fileName; - bool m_eof; - class AAC_File *m_aacFile; -}; - -#endif - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h b/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h deleted file mode 100644 index 870482c1f..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/AacSource_p.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include - -class AAC_File -{ -public: - AAC_File(const QString&, int headerType); - virtual ~AAC_File(); - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) = 0; - virtual bool init() = 0; - //virtual QString getMbid() = 0; - virtual void skip( const int mSecs ) = 0; - virtual void postDecode(unsigned long) = 0; - - enum HeaderType - { - AAC_UNKNOWN = 0, - AAC_ADIF, - AAC_ADTS, - AAC_MP4 - }; - - QString m_fileName; - unsigned char *m_inBuf; - size_t m_inBufSize; - NeAACDecHandle m_decoder; - unsigned char *m_overflow; - size_t m_overflowSize; - int m_header; -}; - - -class AAC_MP4_File : public AAC_File -{ -public: - AAC_MP4_File(const QString&, int headerType = AAC_MP4 ); - ~AAC_MP4_File(); - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ); - virtual bool init(); - //virtual QString getMbid(); - virtual void skip( const int mSecs ); - virtual void postDecode(unsigned long); - int32_t readSample(); - -private: - bool commonSetup( NeAACDecHandle& handle, mp4ff_callback_t*& cb, FILE*& fp, mp4ff_t*& mp4, int32_t& audioTrack ); - virtual int32_t getTrack( const mp4ff_t* f ); - int m_mp4AudioTrack; - uint32_t m_mp4SampleId; - mp4ff_t *m_mp4File; - mp4ff_callback_t *m_mp4cb; -}; - - -class AAC_ADTS_File : public AAC_File -{ -public: - AAC_ADTS_File( const QString& fileName, int headerType ); - ~AAC_ADTS_File(); - virtual void getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ); - virtual bool init(); - //virtual QString getMbid(); - virtual void skip( const int mSecs ); - virtual void postDecode(unsigned long bytesconsumed ); - -private: - int32_t commonSetup( FILE*& fp, NeAACDecHandle& decoder, unsigned char*& buf, size_t& bufSize, uint32_t& samplerate, uint8_t& channels ); - void parse( FILE*& fp, unsigned char*& buf, size_t& bufSize, int &bitrate, double &length ); - void fillBuffer( FILE*& fp, unsigned char*& buf, size_t& bufSize, const size_t m_bytesConsumed ); - - FILE* m_file; - // These two only needed for skipping AAC ADIF files - uint32_t m_adifSamplerate; - int m_adifChannels; -}; diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp deleted file mode 100644 index 1e1e29900..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "FlacSource.h" -#include -#include -#include -#include -#include -#include -#include - -#include - - -FLAC__StreamDecoderWriteStatus FlacSource::_write_callback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - assert(client_data != NULL); - FlacSource *instance = reinterpret_cast(client_data); - assert(instance != NULL); - return instance->write_callback(frame, buffer); -} - -FLAC__StreamDecoderWriteStatus FlacSource::write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) -{ - m_outBufLen = 0; - - if ( m_outBuf ) - { - size_t i; - for(i = 0; i < frame->header.blocksize; i++) - { - switch ( m_channels ) - { - case 1: - m_outBuf[m_outBufLen] = (FLAC__int16)buffer[0][i]; // mono - m_outBufLen++; - break; - case 2: - m_outBuf[m_outBufLen] = (FLAC__int16)buffer[0][i]; // left channel - m_outBuf[m_outBufLen+1] = (FLAC__int16)buffer[1][i]; // right channel - m_outBufLen += 2; - break; - } - } - m_samplePos += frame->header.blocksize; - } - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -// --------------------------------------------------------------------- - -void FlacSource::_metadata_callback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data) -{ - assert(client_data != NULL); - FlacSource *instance = reinterpret_cast(client_data); - assert(instance != NULL); - instance->metadata_callback(metadata); -} - -void FlacSource::metadata_callback( const FLAC__StreamMetadata *metadata ) -{ - switch ( metadata->type ) - { - case FLAC__METADATA_TYPE_STREAMINFO: - m_channels = metadata->data.stream_info.channels; - m_totalSamples = metadata->data.stream_info.total_samples; - m_samplerate = metadata->data.stream_info.sample_rate; - m_bps = metadata->data.stream_info.bits_per_sample; - m_maxFrameSize = metadata->data.stream_info.max_framesize; - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - m_commentData = FLAC__metadata_object_clone(metadata); - break; - default: - break; - } -} - -// --------------------------------------------------------------------- - -void FlacSource::_error_callback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - assert(client_data != NULL); - FlacSource *instance = reinterpret_cast(client_data); - assert(instance != NULL); - instance->error_callback(status); -} - -void FlacSource::error_callback(FLAC__StreamDecoderErrorStatus status) -{ - std::cerr << "Got FLAC error: " << FLAC__StreamDecoderErrorStatusString[status] << std::endl; -} - -// --------------------------------------------------------------------- - -FlacSource::FlacSource() - : m_decoder( 0 ) - , m_fileSize( 0 ) - , m_outBuf( 0 ) - , m_outBufLen( 0 ) - , m_outBufPos( 0 ) - , m_samplePos( 0 ) - , m_maxFrameSize( 0 ) - , m_commentData( 0 ) - , m_bps( 0 ) - , m_channels( 0 ) - , m_samplerate( 0 ) - , m_totalSamples( 0 ) - , m_eof( false ) -{ -} - -// --------------------------------------------------------------------- - -FlacSource::~FlacSource() -{ - if ( m_decoder ) - { - FLAC__stream_decoder_finish( m_decoder ); - FLAC__stream_decoder_delete( m_decoder ); - } - if ( m_commentData ) - FLAC__metadata_object_delete( m_commentData ); - if ( m_outBuf ) - free( m_outBuf ); -} - -// --------------------------------------------------------------------- - -void FlacSource::init(const QString& fileName) -{ - m_fileName = fileName; - - if ( !m_decoder ) - { - FILE *f = fopen(QFile::encodeName(m_fileName), "rb" ); - if ( f ) - { - // Need to check which init call to use; flac doesn't do that for us - unsigned char header[35]; - bool isOgg = false; - fread( header, 1, 35, f ); - if ( memcmp(header, "OggS", 4) == 0 && - memcmp(&header[29], "FLAC", 4) == 0 ) - isOgg = true; - - // getInfo() will need this to calculate bitrate - fseek( f, 0, SEEK_END ); - m_fileSize = ftell(f); - - rewind( f ); - - m_decoder = FLAC__stream_decoder_new(); - FLAC__stream_decoder_set_metadata_respond(m_decoder, FLAC__METADATA_TYPE_STREAMINFO); - FLAC__stream_decoder_set_metadata_respond(m_decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); - - int init_status; - if ( FLAC_API_SUPPORTS_OGG_FLAC && isOgg ) - init_status = FLAC__stream_decoder_init_ogg_FILE( m_decoder, f, _write_callback, _metadata_callback, _error_callback, this ); - else - init_status = FLAC__stream_decoder_init_FILE( m_decoder, f, _write_callback, _metadata_callback, _error_callback, this ); - - if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) - return; - - FLAC__stream_decoder_process_until_end_of_metadata( m_decoder ); - m_outBuf = static_cast(malloc( sizeof(signed short)*m_maxFrameSize)); - - if ( m_bps != 16 ) - { - FLAC__stream_decoder_finish( m_decoder ); - FLAC__stream_decoder_delete( m_decoder ); - FLAC__metadata_object_delete( m_commentData ); - m_decoder = 0; - m_commentData = 0; - throw std::runtime_error( "ERROR: only 16 bit FLAC files are currently supported!" ); - } - } - else - throw std::runtime_error( "ERROR: cannot load FLAC file!" ); - } -} - -// --------------------------------------------------------------------- - -/*QString FlacSource::getMbid() -{ - if ( m_commentData ) - { - FLAC__StreamMetadata_VorbisComment *vc; - vc = &m_commentData->data.vorbis_comment; - for ( unsigned int i = 0; i < vc->num_comments; ++i ) - { - QByteArray key( (char*)(vc->comments[i].entry), vc->comments[i].length ); - if ( key.left(20).toLower() == "musicbrainz_trackid=" ) - { - QString val = key.mid(20); - return val; - } - } - } - - return QString(); -}*/ - -// --------------------------------------------------------------------- - -void FlacSource::getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels) -{ - lengthSecs = 0; - samplerate = 0; - bitrate = 0; - nchannels = 0; - - if ( m_decoder ) - { - samplerate = m_samplerate; - nchannels = m_channels; - if ( samplerate > 0 ) - lengthSecs = static_cast( static_cast(m_totalSamples)/m_samplerate + 0.5); - - // Calcuate bitrate - if ( lengthSecs > 0 ) - { - FLAC__Metadata_SimpleIterator *it = FLAC__metadata_simple_iterator_new(); - FLAC__metadata_simple_iterator_init( it, QFile::encodeName(m_fileName), true, true ); - while( !FLAC__metadata_simple_iterator_is_last( it ) ) - { - FLAC__metadata_simple_iterator_next( it ); - } - off_t audioOffset = FLAC__metadata_simple_iterator_get_block_offset( it ) + - FLAC__metadata_simple_iterator_get_block_length( it ); - FLAC__metadata_simple_iterator_delete( it ); - bitrate = static_cast( static_cast(m_fileSize - audioOffset) * 8 / lengthSecs + 0.5 ); - } - } -} - -// --------------------------------------------------------------------- - -void FlacSource::skip( const int mSecs ) -{ - FLAC__uint64 absSample = mSecs * m_samplerate / 1000 + m_samplePos; - if ( !FLAC__stream_decoder_seek_absolute(m_decoder, absSample) ) - FLAC__stream_decoder_reset( m_decoder ); - m_outBufLen = 0; -} - -// --------------------------------------------------------------------- - -void FlacSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - silenceThreshold *= static_cast( std::numeric_limits::max() ); - for ( ;; ) - { - double sum = 0; - bool result = FLAC__stream_decoder_process_single( m_decoder ); - // there was a fatal read - if ( !result ) - break; - - switch ( m_channels ) - { - case 1: - for (size_t j = 0; j < m_outBufLen; ++j) - sum += abs( m_outBuf[j] ); - break; - case 2: - for ( size_t j = 0; j < m_outBufLen; j+=2 ) - sum += abs( (m_outBuf[j] >> 1) - + (m_outBuf[j+1] >> 1) ); - break; - } - if ( (sum >= silenceThreshold * static_cast(m_outBufLen) ) ) - break; - } - m_outBufLen = 0; -} - -// --------------------------------------------------------------------- - -int FlacSource::updateBuffer( signed short *pBuffer, size_t bufferSize ) -{ - size_t nwrit = 0; - - for ( ;; ) - { - size_t samples_to_use = std::min (bufferSize - nwrit, m_outBufLen - m_outBufPos); - signed short* pBufferIt = pBuffer + nwrit; - - nwrit += samples_to_use; - assert( nwrit <= bufferSize ); - memcpy( pBufferIt, m_outBuf + m_outBufPos, sizeof(signed short)*samples_to_use ); - - if ( samples_to_use < m_outBufLen - m_outBufPos ) - m_outBufPos = samples_to_use; - else - { - m_outBufPos = 0; - bool result = FLAC__stream_decoder_process_single( m_decoder ); - // there was a fatal read - if ( !result ) - { - std::cerr << "Fatal error decoding FLAC" << std::endl; - return 0; - } - else if ( FLAC__stream_decoder_get_state( m_decoder ) == FLAC__STREAM_DECODER_END_OF_STREAM ) - { - m_eof = true; - break; - } - } - - if ( nwrit == bufferSize ) - return static_cast(nwrit); - } - return static_cast(nwrit); -} - -// ----------------------------------------------------------------------------- - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h deleted file mode 100644 index 24dd97f11..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/FlacSource.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FLAC_SOURCE_H__ -#define __FLAC_SOURCE_H__ - -#include -#include -#include - - -class FlacSource : public lastfm::FingerprintableSource -{ -public: - FlacSource(); - virtual ~FlacSource(); - - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - - // return a chunk of PCM data from the FLAC file - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - - //QString getMbid(); - - bool eof() const { return m_eof; } - -private: - static FLAC__StreamDecoderWriteStatus _write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - static void _metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - static void _error_callback(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data); - - FLAC__StreamDecoderWriteStatus write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); - void metadata_callback( const FLAC__StreamMetadata *metadata ); - void error_callback(FLAC__StreamDecoderErrorStatus status); - - FLAC__StreamDecoder *m_decoder; - QString m_fileName; - size_t m_fileSize; - short *m_outBuf; - size_t m_outBufLen; - size_t m_outBufPos; - FLAC__uint64 m_samplePos; - unsigned m_maxFrameSize; - FLAC__StreamMetadata* m_commentData; - unsigned m_bps; - unsigned m_channels; - unsigned m_samplerate; - FLAC__uint64 m_totalSamples; - - bool m_eof; -}; - -#endif - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp deleted file mode 100644 index 00e725ae6..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "MadSource.h" - -#undef max // was definded in mad - -using namespace std; - - -// ----------------------------------------------------------- - -MadSource::MadSource() - : m_pMP3_Buffer ( new unsigned char[m_MP3_BufferSize+MAD_BUFFER_GUARD] ) -{} - -// ----------------------------------------------------------- - -MadSource::~MadSource() -{ - if ( m_inputFile.isOpen() ) - { - m_inputFile.close(); - mad_synth_finish(&m_mad_synth); - mad_frame_finish(&m_mad_frame); - mad_stream_finish(&m_mad_stream); - } - if (m_pMP3_Buffer) delete[] m_pMP3_Buffer; -} - -// --------------------------------------------------------------------- - -inline short f2s(mad_fixed_t f) -{ - /* A fixed point number is formed of the following bit pattern: - * - * SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF - * MSB LSB - * S ==> Sign (0 is positive, 1 is negative) - * W ==> Whole part bits - * F ==> Fractional part bits - * - * This pattern contains MAD_F_FRACBITS fractional bits, one - * should alway use this macro when working on the bits of a fixed - * point number. It is not guaranteed to be constant over the - * different platforms supported by libmad. - * - * The signed short value is formed, after clipping, by the least - * significant whole part bit, followed by the 15 most significant - * fractional part bits. Warning: this is a quick and dirty way to - * compute the 16-bit number, madplay includes much better - * algorithms. - */ - - /* Clipping */ - if(f >= MAD_F_ONE) - return(SHRT_MAX); - if(f <= -MAD_F_ONE) - return(-SHRT_MAX); - - /* Conversion. */ - f = f >> (MAD_F_FRACBITS-15); - return (signed short)f; -} - -// --------------------------------------------------------------------- - -string MadSource::MadErrorString(const mad_error& error) -{ - switch(error) - { - /* Generic unrecoverable errors. */ - case MAD_ERROR_BUFLEN: - return("input buffer too small (or EOF)"); - case MAD_ERROR_BUFPTR: - return("invalid (null) buffer pointer"); - case MAD_ERROR_NOMEM: - return("not enough memory"); - - /* Frame header related unrecoverable errors. */ - case MAD_ERROR_LOSTSYNC: - return("lost synchronization"); - case MAD_ERROR_BADLAYER: - return("reserved header layer value"); - case MAD_ERROR_BADBITRATE: - return("forbidden bitrate value"); - case MAD_ERROR_BADSAMPLERATE: - return("reserved sample frequency value"); - case MAD_ERROR_BADEMPHASIS: - return("reserved emphasis value"); - - /* Recoverable errors */ - case MAD_ERROR_BADCRC: - return("CRC check failed"); - case MAD_ERROR_BADBITALLOC: - return("forbidden bit allocation value"); - case MAD_ERROR_BADSCALEFACTOR: - return("bad scalefactor index"); - case MAD_ERROR_BADFRAMELEN: - return("bad frame length"); - case MAD_ERROR_BADBIGVALUES: - return("bad big_values count"); - case MAD_ERROR_BADBLOCKTYPE: - return("reserved block_type"); - case MAD_ERROR_BADSCFSI: - return("bad scalefactor selection info"); - case MAD_ERROR_BADDATAPTR: - return("bad main_data_begin pointer"); - case MAD_ERROR_BADPART3LEN: - return("bad audio data length"); - case MAD_ERROR_BADHUFFTABLE: - return("bad Huffman table select"); - case MAD_ERROR_BADHUFFDATA: - return("Huffman data overrun"); - case MAD_ERROR_BADSTEREO: - return("incompatible block_type for JS"); - - /* Unknown error. This switch may be out of sync with libmad's - * defined error codes. - */ - default: - return("Unknown error code"); - } -} - - -// ----------------------------------------------------------------------------- - -bool MadSource::isRecoverable(const mad_error& error, bool log) -{ - if (MAD_RECOVERABLE (error)) - { - /* Do not print a message if the error is a loss of - * synchronization and this loss is due to the end of - * stream guard bytes. (See the comments marked {3} - * supra for more informations about guard bytes.) - */ - if (error != MAD_ERROR_LOSTSYNC /*|| mad_stream.this_frame != pGuard */ && log) - { - cerr << "Recoverable frame level error: " - << MadErrorString(error) << endl; - } - - return true; - } - else - { - if (error == MAD_ERROR_BUFLEN) - return true; - else - { - stringstream ss; - - ss << "Unrecoverable frame level error: " - << MadErrorString (error) << endl; - throw ss.str(); - } - } - - return false; -} - -// ----------------------------------------------------------- - -void MadSource::init(const QString& fileName) -{ - m_inputFile.setFileName( m_fileName = fileName ); - bool fine = m_inputFile.open( QIODevice::ReadOnly ); - - if ( !fine ) - { - throw std::runtime_error ("Cannot load mp3 file!"); - } - - mad_stream_init(&m_mad_stream); - mad_frame_init (&m_mad_frame); - mad_synth_init (&m_mad_synth); - mad_timer_reset(&m_mad_timer); - - m_pcmpos = m_mad_synth.pcm.length; -} - -// ----------------------------------------------------------------------------- - -/*QString MadSource::getMbid() -{ - char out[MBID_BUFFER_SIZE]; - int const r = getMP3_MBID( QFile::encodeName( m_fileName ), out ); - if (r == 0) - return QString::fromLatin1( out ); - return QString(); -}*/ - -void MadSource::getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels ) -{ - // get the header plus some other stuff.. - QFile inputFile(m_fileName); - bool fine = inputFile.open( QIODevice::ReadOnly ); - - if ( !fine ) - { - throw std::runtime_error ("ERROR: Cannot load file for getInfo!"); - return; - } - - unsigned char* pMP3_Buffer = new unsigned char[m_MP3_BufferSize+MAD_BUFFER_GUARD]; - - mad_stream madStream; - mad_header madHeader; - mad_timer_t madTimer; - - mad_stream_init(&madStream); - mad_timer_reset(&madTimer); - - double avgSamplerate = 0; - double avgBitrate = 0; - double avgNChannels = 0; - int nFrames = 0; - - while ( fetchData( inputFile, pMP3_Buffer, m_MP3_BufferSize, madStream) ) - { - if ( mad_header_decode(&madHeader, &madStream) != 0 ) - { - if ( isRecoverable(madStream.error) ) - continue; - else - break; - } - - mad_timer_add(&madTimer, madHeader.duration); - - avgSamplerate += madHeader.samplerate; - avgBitrate += madHeader.bitrate; - - if ( madHeader.mode == MAD_MODE_SINGLE_CHANNEL ) - ++avgNChannels; - else - avgNChannels += 2; - - ++nFrames; - } - - inputFile.close(); - mad_stream_finish(&madStream); - mad_header_finish(&madHeader); - delete[] pMP3_Buffer; - - - lengthSecs = static_cast(madTimer.seconds); - samplerate = static_cast( (avgSamplerate/nFrames) + 0.5 ); - bitrate = static_cast( (avgBitrate/nFrames) + 0.5 ); - nchannels = static_cast( (avgNChannels/nFrames) + 0.5 ); -} - -// ----------------------------------------------------------- - - -bool MadSource::fetchData( QFile& mp3File, - unsigned char* pMP3_Buffer, - const int MP3_BufferSize, - mad_stream& madStream ) -{ - unsigned char *pReadStart = NULL; - unsigned char *pGuard = NULL; - - if ( madStream.buffer == NULL || - madStream.error == MAD_ERROR_BUFLEN ) - { - - size_t readSize; - size_t remaining; - - /* {2} libmad may not consume all bytes of the input - * buffer. If the last frame in the buffer is not wholly - * contained by it, then that frame's start is pointed by - * the next_frame member of the Stream structure. This - * common situation occurs when mad_frame_decode() fails, - * sets the stream error code to MAD_ERROR_BUFLEN, and - * sets the next_frame pointer to a non NULL value. (See - * also the comment marked {4} bellow.) - * - * When this occurs, the remaining unused bytes must be - * put back at the beginning of the buffer and taken in - * account before refilling the buffer. This means that - * the input buffer must be large enough to hold a whole - * frame at the highest observable bit-rate (currently 448 - * kb/s). XXX=XXX Is 2016 bytes the size of the largest - * frame? (448000*(1152/32000))/8 - */ - if (madStream.next_frame != NULL) - { - remaining = madStream.bufend - madStream.next_frame; - memmove (pMP3_Buffer, madStream.next_frame, remaining); - - pReadStart = pMP3_Buffer + remaining; - readSize = MP3_BufferSize - remaining; - } - else - { - readSize = MP3_BufferSize; - pReadStart = pMP3_Buffer; - remaining = 0; - } - - readSize = mp3File.read( reinterpret_cast(pReadStart), readSize ); - - // nothing else to read! - if (readSize <= 0) - return false; - - if ( mp3File.atEnd() ) - { - pGuard = pReadStart + readSize; - - memset (pGuard, 0, MAD_BUFFER_GUARD); - readSize += MAD_BUFFER_GUARD; - } - - // Pipe the new buffer content to libmad's stream decoder facility. - mad_stream_buffer( &madStream, pMP3_Buffer, - static_cast(readSize + remaining)); - - madStream.error = MAD_ERROR_NONE; - } - - return true; -} - -// ----------------------------------------------------------------------------- - -void MadSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - mad_frame madFrame; - mad_synth madSynth; - - mad_frame_init(&madFrame); - mad_synth_init (&madSynth); - - silenceThreshold *= static_cast( numeric_limits::max() ); - - for (;;) - { - if ( !fetchData( m_inputFile, m_pMP3_Buffer, m_MP3_BufferSize, m_mad_stream) ) - break; - - if ( mad_frame_decode(&madFrame, &m_mad_stream) != 0 ) - { - if ( isRecoverable(m_mad_stream.error) ) - continue; - else - break; - } - - mad_synth_frame (&madSynth, &madFrame); - - double sum = 0; - - switch (madSynth.pcm.channels) - { - case 1: - for (size_t j = 0; j < madSynth.pcm.length; ++j) - sum += abs(f2s(madSynth.pcm.samples[0][j])); - break; - case 2: - for (size_t j = 0; j < madSynth.pcm.length; ++j) - sum += abs(f2s( - (madSynth.pcm.samples[0][j] >> 1) - + (madSynth.pcm.samples[1][j] >> 1))); - break; - } - - if ( (sum >= silenceThreshold * madSynth.pcm.length) ) - break; - } - - mad_frame_finish(&madFrame); -} - -// ----------------------------------------------------------------------------- - -void MadSource::skip(const int mSecs) -{ - if ( mSecs <= 0 ) - return; - - mad_header madHeader; - mad_header_init(&madHeader); - - for (;;) - { - if (!fetchData( m_inputFile, m_pMP3_Buffer, m_MP3_BufferSize, m_mad_stream)) - break; - - if ( mad_header_decode(&madHeader, &m_mad_stream) != 0 ) - { - if ( isRecoverable(m_mad_stream.error) ) - continue; - else - break; - } - - mad_timer_add(&m_mad_timer, madHeader.duration); - - if ( mad_timer_count(m_mad_timer, MAD_UNITS_MILLISECONDS) >= mSecs ) - break; - } - - mad_header_finish(&madHeader); -} - -// ----------------------------------------------------------- - -int MadSource::updateBuffer(signed short* pBuffer, size_t bufferSize) -{ - size_t nwrit = 0; //number of samples written to the output buffer - - for (;;) - { - // get a (valid) frame - // m_pcmpos == 0 could mean two things - // - we have completely decoded a frame, but the output buffer is still - // not full (it would make more sense for pcmpos == pcm.length(), but - // the loop assigns pcmpos = 0 at the end and does it this way! - // - we are starting a stream - if ( m_pcmpos == m_mad_synth.pcm.length ) - { - if ( !fetchData( m_inputFile, m_pMP3_Buffer, m_MP3_BufferSize, m_mad_stream) ) - { - break; // nothing else to read - } - - // decode the frame - if (mad_frame_decode (&m_mad_frame, &m_mad_stream)) - { - if ( isRecoverable(m_mad_stream.error) ) - continue; - else - break; - } // if (mad_frame_decode (&madFrame, &madStream)) - - mad_timer_add (&m_mad_timer, m_mad_frame.header.duration); - mad_synth_frame (&m_mad_synth, &m_mad_frame); - - m_pcmpos = 0; - } - - size_t samples_for_mp3 = m_mad_synth.pcm.length - m_pcmpos; - size_t samples_for_buf = bufferSize - nwrit; - signed short* pBufferIt = pBuffer + nwrit; - size_t i = 0, j = 0; - - switch( m_mad_synth.pcm.channels ) - { - case 1: - { - size_t samples_to_use = min (samples_for_mp3, samples_for_buf); - for (i = 0; i < samples_to_use; ++i ) - pBufferIt[i] = f2s( m_mad_synth.pcm.samples[0][i+m_pcmpos] ); - } - j = i; - break; - - case 2: - for (; i < samples_for_mp3 && j < samples_for_buf ; ++i, j+=2 ) - { - pBufferIt[j] = f2s( m_mad_synth.pcm.samples[0][i+m_pcmpos] ); - pBufferIt[j+1] = f2s( m_mad_synth.pcm.samples[1][i+m_pcmpos] ); - } - break; - - default: - cerr << "wtf kind of mp3 has " << m_mad_synth.pcm.channels << " channels??\n"; - break; - } - - m_pcmpos += i; - nwrit += j; - - assert( nwrit <= bufferSize ); - - if (nwrit == bufferSize) - return static_cast(nwrit); - } - - return static_cast(nwrit); -} - -// ----------------------------------------------------------------------------- - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h deleted file mode 100644 index c22cb6d5d..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/MadSource.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef __MP3_SOURCE_H__ -#define __MP3_SOURCE_H__ - -#include -#include -#include -#include -#include -#include - - -class MadSource : public lastfm::FingerprintableSource -{ -public: - MadSource(); - ~MadSource(); - - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - virtual bool eof() const { return m_inputFile.atEnd(); } - -private: - static bool fetchData( QFile& mp3File, - unsigned char* pMP3_Buffer, - const int MP3_BufferSize, - mad_stream& madStream ); - - static bool isRecoverable(const mad_error& error, bool log = false); - - static std::string MadErrorString(const mad_error& error); - - struct mad_stream m_mad_stream; - struct mad_frame m_mad_frame; - mad_timer_t m_mad_timer; - struct mad_synth m_mad_synth; - - QFile m_inputFile; - - unsigned char* m_pMP3_Buffer; - static const int m_MP3_BufferSize = (5*8192); - QString m_fileName; - - size_t m_pcmpos; -}; - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp deleted file mode 100644 index fd4defb17..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "VorbisSource.h" -#include -#include -#include -#include -#include -#include -#include - -// These specify the output format -static const int wordSize = 2; // 16 bit output -static const int isSigned = 1; -#if __BIG_ENDIAN__ -static const int isBigEndian = 1; -#else -static const int isBigEndian = 0; -#endif - - -VorbisSource::VorbisSource() - : m_channels( 0 ) - , m_samplerate( 0 ) - , m_eof( false ) -{ - memset( &m_vf, 0, sizeof(m_vf) ); -} - -// --------------------------------------------------------------------- - -VorbisSource::~VorbisSource() -{ - // ov_clear() also closes the file - ov_clear( &m_vf ); -} - -// --------------------------------------------------------------------- - -void VorbisSource::init(const QString& fileName) -{ - m_fileName = fileName; - - if ( m_vf.datasource ) - { - std::cerr << "Warning: file already appears to be open"; - return; - } - - FILE *fp = fopen(QFile::encodeName(m_fileName), "rb" ); - if( !fp ) - throw std::runtime_error( "ERROR: Cannot open ogg file!" ); - - // See the warning about calling ov_open on Windows - if ( ov_test_callbacks( fp, &m_vf, NULL, 0, OV_CALLBACKS_DEFAULT ) < 0 ) - { - fclose( fp ); - throw std::runtime_error( "ERROR: This is not an ogg vorbis file!" ); - } - - ov_test_open( &m_vf ); - - // Don't fingerprint files with more than one logical bitstream - // They most likely contain more than one track - if ( ov_streams( &m_vf ) != 1 ) - throw std::runtime_error( "ERROR: ogg file contains multiple bitstreams" ); - - m_channels = ov_info( &m_vf, 0 )->channels; - m_samplerate = static_cast(ov_info( &m_vf, 0 )->rate); - m_eof = false; -} - -void VorbisSource::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels) -{ - // stream info - nchannels = ov_info( &m_vf, -1 )->channels; - samplerate = static_cast(ov_info( &m_vf, -1 )->rate); - lengthSecs = static_cast(ov_time_total( &m_vf, -1 ) + 0.5); - bitrate = static_cast(ov_bitrate( &m_vf, -1 )); -} - -// --------------------------------------------------------------------- - -void VorbisSource::skip( const int mSecs ) -{ - if ( mSecs < 0 ) - return; - - double ts = mSecs / 1000.0 + ov_time_tell( &m_vf ); - ov_time_seek( &m_vf, ts ); -} - -// --------------------------------------------------------------------- - -void VorbisSource::skipSilence(double silenceThreshold /* = 0.0001 */) -{ - silenceThreshold *= static_cast( std::numeric_limits::max() ); - - char sampleBuffer[4096]; - int bs = 0; - for (;;) - { - long charReadBytes = ov_read( &m_vf, sampleBuffer, 4096, isBigEndian, wordSize, isSigned, &bs ); - - // eof - if ( !charReadBytes ) - { - m_eof = true; - break; - } - if ( charReadBytes < 0 ) - { - // a bad bit of data: OV_HOLE || OV_EBADLINK - continue; - } - else if ( charReadBytes > 0 ) - { - double sum = 0; - int16_t *buf = reinterpret_cast(sampleBuffer); - switch ( m_channels ) - { - case 1: - for (long j = 0; j < charReadBytes/wordSize; j++) - sum += abs( buf[j] ); - break; - case 2: - for (long j = 0; j < charReadBytes/wordSize; j+=2) - sum += abs( (buf[j] >> 1) + (buf[j+1] >> 1) ); - break; - } - if ( sum >= silenceThreshold * static_cast(charReadBytes/wordSize/m_channels) ) - break; - } - } -} - -// --------------------------------------------------------------------- - -int VorbisSource::updateBuffer( signed short *pBuffer, size_t bufferSize ) -{ - char buf[ bufferSize * wordSize ]; - int bs = 0; - size_t charwrit = 0; //number of samples written to the output buffer - - for (;;) - { - long charReadBytes = ov_read( &m_vf, buf, static_cast(bufferSize * wordSize - charwrit), - isBigEndian, wordSize, isSigned, &bs ); - if ( !charReadBytes ) - { - m_eof = true; - break; // nothing else to read - } - - // Don't really need this though since we're excluding files that have - // more than one logical bitstream - if ( bs != 0 ) - { - vorbis_info *vi = ov_info( &m_vf, -1 ); - if ( m_channels != vi->channels || m_samplerate != vi->rate ) - { - std::cerr << "Files that change channel parameters or samplerate are currently not supported" << std::endl; - return 0; - } - } - - if( charReadBytes < 0 ) - { - std::cerr << "Warning: corrupt section of data, attempting to continue..." << std::endl; - continue; - } - - char* pBufferIt = reinterpret_cast(pBuffer) + charwrit; - charwrit += charReadBytes; - - assert( charwrit <= bufferSize * wordSize ); - memcpy( pBufferIt, buf, charReadBytes ); - - if (charwrit == bufferSize * wordSize) - return static_cast(charwrit/wordSize); - } - - return static_cast(charwrit/wordSize); -} - -// ----------------------------------------------------------------------------- - diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h b/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h deleted file mode 100644 index 988ce6239..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __VORBIS_SOURCE_H__ -#define __VORBIS_SOURCE_H__ - -#include -#include - - -class VorbisSource : public lastfm::FingerprintableSource -{ -public: - VorbisSource(); - ~VorbisSource(); - virtual void getInfo(int& lengthSecs, int& samplerate, int& bitrate, int& nchannels); - virtual void init(const QString& fileName); - virtual int updateBuffer(signed short* pBuffer, size_t bufferSize); - virtual void skip(const int mSecs); - virtual void skipSilence(double silenceThreshold = 0.0001); - virtual bool eof() const { return m_eof; } - -private: - OggVorbis_File m_vf; - QString m_fileName; - int m_channels; - int m_samplerate; - bool m_eof; -}; - -#endif diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro b/thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro deleted file mode 100644 index bd615e723..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/lastfm-fingerprint.pro +++ /dev/null @@ -1,13 +0,0 @@ -QT = core xml network -LIBS += -L$$DESTDIR -llastfm -llastfm_fingerprint -LIBS += -lvorbisfile -lFLAC -lfaad -lmp4ff -lmad -SOURCES = AacSource.cpp FlacSource.cpp MadSource.cpp VorbisSource.cpp main.cpp - -mac { - INCLUDEPATH += /opt/local/include - LIBS += -L/opt/local/lib - - DEFINES += MACPORTS_SUCKS - SOURCES -= AacSource.cpp - LIBS -= -lmp4ff -} diff --git a/thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp b/thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp deleted file mode 100644 index 3b035f2d8..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/contrib/main.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - Copyright 2009 John Stamp - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -// ubuntu 9.04: sudo apt-get install libmad0-dev libvorbis-dev libflac-dev libfaac-dev -// macports: sudo port install libmad libvorbis libflac -// Windows: lol - -#include "MadSource.h" -#include "VorbisSource.h" -#include "FlacSource.h" -#include "AacSource.h" -#include -#include -#include -#include -#include -int typeOf(const QString& path); -lastfm::FingerprintableSource* factory(int type); -enum { MP3, OGG, FLAC, AAC, UNKNOWN }; -namespace lastfm { Track taglib(const QString& path); } - - -int main(int argc, char** argv) try -{ - if (argc < 2) { - std::cerr << "usage: " << argv[0] << " path" << std::endl; - return 1; - } - - QCoreApplication app(argc, argv); - QEventLoop loop; - - QString const path = QFile::decodeName(argv[1]); - - lastfm::Track t = lastfm::taglib(path); //see contrib //TODO mbid - lastfm::Fingerprint fp(t); - if (fp.id().isNull()) { - lastfm::FingerprintableSource* src = factory(typeOf(path)); - fp.generate(src); - QNetworkReply* reply = fp.submit(); - loop.connect(reply, SIGNAL(finished()), SLOT(quit())); - fp.decode(reply); - } - - QNetworkReply* reply = fp.id().getSuggestions(); - loop.connect(reply, SIGNAL(finished()), SLOT(quit())); - - std::cout << reply->readAll().data() << std::endl; //returns XML - return 0; -} -catch (std::exception& e) -{ - std::cerr << e.what() << std::endl; -} - -lastfm::FingerprintableSource* factory(int type) -{ - switch (type) { - case MP3: return new MadSource; - case OGG: return new VorbisSource; - case FLAC: return new FlacSource; - #ifndef MACPORTS_SUCKS - case AAC: return new AacSource; - #endif - default: throw std::runtime_error("Cannot handle filetype"); - } -} - -int typeOf(const QString& fileName) -{ - QStringList parts = fileName.split( "." ); - QString extension; - if ( parts.size() > 1 ) - extension = parts.last(); - - // Let's be trusting about extensions - if ( extension.toLower() == "mp3" ) - return MP3; - else if ( extension.toLower() == "ogg" ) - return OGG; - else if ( extension.toLower() == "oga" ) - return FLAC; - else if ( extension.toLower() == "flac" ) - return FLAC; - else if ( extension.toLower() == "aac" ) - return AAC; - else if ( extension.toLower() == "m4a" ) - return AAC; - - // So much for relying on extensions. Let's try file magic instead. - FILE *fp = NULL; - unsigned char header[35]; - - fp = fopen(QFile::encodeName(fileName), "rb"); - if ( !fp ) - { - return UNKNOWN; - } - int fType = UNKNOWN; - fread( header, 1, 35, fp ); - - // Some formats can have ID3 tags (or not), so let's just - // get them out of the way first before we check what we have. - if ( memcmp( header, "ID3", 3) == 0 ) - { - int tagsize = 0; - /* high bit is not used */ - tagsize = (header[6] << 21) | (header[7] << 14) | - (header[8] << 7) | (header[9] << 0); - - tagsize += 10; - fseek( fp, tagsize, SEEK_SET ); - fread( header, 1, 35, fp ); - } - - if ( (header[0] == 0xFF) && ((header[1] & 0xFE) == 0xFA ) ) - { - fType = MP3; - } - else if ( memcmp(header, "OggS", 4) == 0 ) - { - if ( memcmp(&header[29], "vorbis", 6) == 0 ) - { - // ogg vorbis (.ogg) - fType = OGG; - } - else if ( memcmp(&header[29], "FLAC", 4) == 0 ) - { - // ogg flac (.oga) - fType = FLAC; - } - } - else if ( memcmp(header, "fLaC", 4 ) == 0 ) - { - // flac file - fType = FLAC; - } - else if ( (header[0] == 0xFF) && ((header[1] & 0xF6) == 0xF0) ) - { - // aac adts - fType = AAC; - } - else if (memcmp(header, "ADIF", 4) == 0) - { - // aac adif - fType = AAC; - } - else if ( memcmp( &header[4], "ftyp", 4 ) == 0 ) - { - // mp4 header: aac - fType = AAC; - } - - fclose(fp); - return fType; -} diff --git a/thirdparty/liblastfm2/src/fingerprint/fingerprint.pro b/thirdparty/liblastfm2/src/fingerprint/fingerprint.pro deleted file mode 100644 index 043ad7bfb..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fingerprint.pro +++ /dev/null @@ -1,25 +0,0 @@ -TEMPLATE = lib -TARGET = lastfm_fingerprint -LIBS += -L$$DESTDIR -llastfm -QT = core xml network sql -include( _files.qmake ) -DEFINES += LASTFM_FINGERPRINT_LIB - -INSTALLS = target -target.path = /lib - -mac:CONFIG( app_bundle ) { - LIBS += libfftw3f.a libsamplerate.a -L/opt/local/include - INCLUDEPATH += /opt/local/include:/opt/qt/qt-current/lib/QtSql.framework/Include/ -}else{ - INCLUDEPATH += /opt/qt/qt-current/lib/QtSql.framework/Include/ - CONFIG += link_pkgconfig - PKGCONFIG += samplerate - win32 { - CONFIG += link_pkgconfig - DEFINES += __NO_THREAD_CHECK - QMAKE_LFLAGS_DEBUG += /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcmt.lib - } - PKGCONFIG += fftw3f - -} diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h b/thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h deleted file mode 100644 index bfec5a8fd..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/CircularArray.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __CIRCULAR_ARRAY_H -#define __CIRCULAR_ARRAY_H - -#include -#include -#include -#include -#include // for memset -#include // for max - -#ifndef NULL -#define NULL 0 -#endif - -template< typename T > -class CircularArray -{ - -public: - - typedef size_t size_type; - - ///////////////////////////////////////////////////////////// - - // IMPORTANT: The distance must be redefined!! - // See declaration of iterator from stl_iterator_base_types.h: - // template - // struct iterator { ... - - // ---------- Forward declarations - - class iterator : - public std::iterator - { - // it should be by default because is an inner class, but I put it just to be sure.. - friend class CircularArray; - - private: - iterator( size_type idx, T* pData, size_type size ) : _idx(idx), _pData(pData), _size(size) {} - - public: - - //typedef random_access_iterator_tag iterator_category; - - iterator() : _idx(0), _pData(NULL) {} - - iterator& operator++() - { // preincrement - _idx = (_idx + 1) % _size; - return (*this); - } - - iterator operator++(int) - { // postincrement - iterator _Tmp = *this; - _idx = (_idx + 1) % _size; - return (_Tmp); - } - - void operator+=(size_type offs) - { - this->_idx = (_idx + offs) % _size; - } - - iterator operator+(size_type offs) const - { - size_type newIdx = (_idx + offs) % _size; - iterator _Tmp(newIdx, _pData, _size); - return _Tmp; - } - - // return the distance between this iterator and it - size_t operator-(const iterator& it) const - { - if ( this->_idx > it._idx ) - return this->_idx - it._idx; - else - return this->_idx + (_size - it._idx); - } - - iterator operator-(size_type offs) const - { - size_type newIdx; - - if ( offs <= _idx ) - newIdx = _idx - offs; - else - newIdx = _size - ((_idx - offs) % _size); // note: should be ok, but to be checked better - - iterator _Tmp(newIdx, _pData, _size); - return _Tmp; - } - - iterator& operator--() - { // predecrement - if (_idx == 0) - _idx = _size - 1; - else - --_idx; - return (*this); - } - - iterator operator--(int) - { // postdecrement - iterator _Tmp = *this; - if (_idx == 0) - _idx = _size - 1; - else - --_idx; - return (_Tmp); - } - - T& operator*() const - { // return designated object - return _pData[_idx]; - } - - T* operator->() const - { // return pointer to class object - return &_pData[_idx]; - } - - /* T& operator=(const T& right) - { // assign reference right to _val - return ( this->_idx = right._idx ); - }*/ - - bool operator==(const iterator& right) const - { // test for iterator equality - return ( this->_idx == right._idx ); - } - - bool operator!=(const iterator& right) const - { // test for iterator inequality - return ( this->_idx != right._idx ); - } - - protected: - size_type _idx; - T* _pData; - size_type _size; - }; - - ///////////////////////////////////////////////////////////// - - - CircularArray() - : _headIdx(0), _pData(NULL), _size(0) - { } - - CircularArray( size_type size ) - : _headIdx(0), _pData(NULL) - { - this->resize(size); - } - - CircularArray( size_type size, const T& init ) - : _headIdx(0), _pData(NULL) - { - this->resize(size, init); - } - - ~CircularArray() - { - this->clear(); - } - - // remember: it is not working (yet!) with negative numbers! - T& operator[](size_type offset) - { - return _pData[ (_headIdx + offset) % _size ]; - } - - void resize( size_type size ) - { - _headIdx = 0; - if ( size == _size ) - return; - - this->clear(); - _pData = new T[size]; - _size = size; - } - - void resize( size_type size, const T& init ) - { - this->resize(size, false); - this->fill(init); - } - - void fill( const T& val ) - { - for (size_type i=0; i<_size; ++i) - _pData[i] = val; - } - - void zero_fill() - { - memset( _pData, 0, _size * sizeof(T) ); - } - - bool empty() const - { - return ( _pData == NULL ); - } - - void clear() - { - if (_pData) - delete [] _pData; - _pData = NULL; - _headIdx = 0; - _size = 0; - } - - iterator head() const - { - if (_pData == NULL) - std::cerr << "WARNING: iterator in CircularArray points to an empty CircularArray" << std::endl; - return iterator(_headIdx, _pData, _size); - } - - void shift_head( int offset ) - { - if ( offset < 0) - { - int mod = (-offset) % (int)_size; - mod -= (int)_headIdx; - _headIdx = _size - mod; - } - else - _headIdx = (_headIdx + offset) % _size; - } - - size_type size() const - { - return _size; - } - - //// to be changed to an input forward iterator - //template - //void get_data( TIterator toFillIt, size_type size = 0 ) - //{ - // if ( size == 0 ) - // size = _size; - // iterator it = head(); - // - // for (size_type i = 0; i < size; ++i) - // *(toFillIt++) = *(it++); - //} - - // IMPORTANT! Destination buffer MUST be the same size! - void copy_buffer( T* pDest ) - { - memcpy( pDest, _pData, sizeof(T)*_size ); - } - - // returns the buffer - T* get_buffer() const - { - return _pData; - } - - -private: - - size_type _headIdx; // index - T* _pData; // array of data - size_type _size; // size of data - -}; - -#endif // __CIRCULAR_ARRAY_H diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp b/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp deleted file mode 100644 index eed4ea3a3..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include // for max -#include - -#include "Filter.h" -#include "fp_helper_fun.h" - -using namespace std; - -namespace fingerprint -{ - -Filter::Filter(unsigned int id, float threshold, float weight) -: id(id), threshold(threshold), weight(weight) -{ - float time_rate = 1.5; - - unsigned int t = 1; - vector time_lengths; - - while (t < KEYWIDTH) - { - time_lengths.push_back(t); - t = max( static_cast( round__(time_rate*t) ) + - static_cast( round__(time_rate*t) % 2), - t+1 ); - } - - unsigned int filter_count = 0; - - for (wt = 1; wt <= time_lengths.size(); wt++) - { - for (wb = 1; wb <= NBANDS; wb++) - { - for (first_band = 1; first_band <= NBANDS - wb + 1; - first_band++) - { - unsigned int time = time_lengths[wt-1]; - filter_count++; - - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 1; - return; - } - - if (time > 1) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 2; - return; - } - } - - if (wb > 1) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 3; - return; - } - } - - if (time > 1 && wb > 1) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 4; - return; - } - } - - if (time > 3) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 5; - return; - } - } - - if (wb > 3) - { - filter_count++; - if (filter_count == id) - { - wt = time_lengths[wt-1]; - filter_type = 6; - return; - } - } - - } // for first_band - } // for wb - } // for wt -} - -} // end of namespace fingerprint - -// ----------------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h b/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h deleted file mode 100644 index 04185eec2..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/Filter.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FILTER_H -#define __FILTER_H - -namespace fingerprint -{ - -struct Filter -{ - /// Constructs a new filter with id. - Filter(unsigned int id, float threshold, float weight); - - unsigned int id; //< filter id - unsigned int wt; //< time width - unsigned int first_band; //< first band - unsigned int wb; //< band width - unsigned int filter_type; //< filter type - - float threshold; //< threshold for filter - float weight; //< filter weight - - // number of frames in time - static const unsigned int KEYWIDTH = 100; - // number of bands to divide the signal (log step) - static const unsigned int NBANDS = 33; -}; - -} - -#endif // __FILTER_H diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp b/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp deleted file mode 100644 index 305aad7b5..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.cpp +++ /dev/null @@ -1,786 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -#include // libsamplerate - -#include "FingerprintExtractor.h" -#include "fp_helper_fun.h" // for GroupData -#include "Filter.h" -#include "FloatingAverage.h" -#include "OptFFT.h" - -////////////////////////////////////////////////////////////////////////// - -namespace fingerprint -{ - -using namespace std; -static const int NUM_FRAMES_CLIENT = 32; // ~= 10 secs. - -enum eProcessType -{ - PT_UNKNOWN, - PT_FOR_QUERY, - PT_FOR_FULLSUBMIT -}; - -////////////////////////////////////////////////////////////////////////// - -class PimplData -{ - -public: - - PimplData() - : m_pDownsampledPCM(NULL), m_pDownsampledCurrIt(NULL), - m_normalizedWindowMs(static_cast(NORMALIZATION_SKIP_SECS * 1000 * 2)), - m_compensateBufferSize(FRAMESIZE-OVERLAPSAMPLES + Filter::KEYWIDTH * OVERLAPSAMPLES), - m_downsampledProcessSize(NUM_FRAMES_CLIENT*FRAMESIZE), - // notice that the buffer has extra space on either side for the normalization window - m_fullDownsampledBufferSize( m_downsampledProcessSize + // the actual processed part - m_compensateBufferSize + // a compensation buffer for the fft - ((m_normalizedWindowMs * DFREQ / 1000) / 2) ), // a compensation buffer for the normalization - m_normWindow(m_normalizedWindowMs * DFREQ / 1000), - m_pFFT(NULL), m_pDownsampleState(NULL), m_processType(PT_UNKNOWN) - { - m_pFFT = new OptFFT(m_downsampledProcessSize + m_compensateBufferSize); - m_pDownsampledPCM = new float[m_fullDownsampledBufferSize]; - - // the end of ||-------m_bufferSize-------|-cb-|---norm/2---|| - // ^-- pEndDownsampledBuf - m_pEndDownsampledBuf = m_pDownsampledPCM + m_fullDownsampledBufferSize; - - // loading filters - size_t numFilters = sizeof(rFilters) / sizeof(RawFilter) ; - for (size_t i = 0; i < numFilters; ++i) - m_filters.push_back( Filter( rFilters[i].ftid, rFilters[i].thresh, rFilters[i].weight ) ); - - } - - ~PimplData() - { - if ( m_pFFT ) - delete m_pFFT; - m_pFFT = NULL; - if ( m_pDownsampledPCM ) - delete [] m_pDownsampledPCM; - m_pDownsampledPCM = NULL; - - if ( m_pDownsampleState ) - src_delete(m_pDownsampleState) ; - - } - - float* m_pDownsampledPCM; - float* m_pDownsampledCurrIt; - - const unsigned int m_normalizedWindowMs; - const size_t m_compensateBufferSize; - const size_t m_downsampledProcessSize; - const size_t m_fullDownsampledBufferSize; - - FloatingAverage m_normWindow; - OptFFT* m_pFFT; - - ////////////////////////////////////////////////////////////////////////// - - // libsamplerate - SRC_STATE* m_pDownsampleState; - SRC_DATA m_downsampleData; - - vector m_floatInData; - - ////////////////////////////////////////////////////////////////////////// - - - bool m_groupsReady; - bool m_preBufferPassed; - - eProcessType m_processType; - - size_t m_toSkipSize; - size_t m_toSkipMs; - - size_t m_skippedSoFar; - bool m_skipPassed; - - float* m_pEndDownsampledBuf; - - int m_freq; - int m_nchannels; - - unsigned int m_lengthMs; - int m_minUniqueKeys; - unsigned int m_uniqueKeyWindowMs; - - unsigned int m_toProcessKeys; - unsigned int m_totalWindowKeys; - - vector m_filters; - - deque m_groupWindow; - vector m_groups; - unsigned int m_processedKeys; - - vector m_partialBits; // here just to avoid reallocation - -#if __BIG_ENDIAN__ - -#define reorderbits(X) ((((unsigned int)(X) & 0xff000000) >> 24) | \ - (((unsigned int)(X) & 0x00ff0000) >> 8) | \ - (((unsigned int)(X) & 0x0000ff00) << 8) | \ - (((unsigned int)(X) & 0x000000ff) << 24)) - - vector m_bigEndianGroups; -#endif -}; - -////////////////////////////////////////////////////////////////////////// - -void initCustom( PimplData& pd, - int freq, int nchannels, - unsigned int lengthMs, unsigned int skipMs, - int minUniqueKeys, unsigned int uniqueKeyWindowMs, int duration ); - -inline float getRMS( const FloatingAverage& signal ); -unsigned int processKeys( deque& groups, size_t size, PimplData& pd ); -void integralImage( float** ppFrames, unsigned int nFrames ); -void computeBits( vector& bits, - const vector& f, - float ** frames, unsigned int nframes ); - - -void src_short_to_float_and_mono_array(const short *in, float *out, int srclen, int nchannels); - -////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- - -FingerprintExtractor::FingerprintExtractor() -: m_pPimplData(NULL) -{ - m_pPimplData = new PimplData(); -} - -// ----------------------------------------------------------------------------- - -FingerprintExtractor::~FingerprintExtractor() -{ - if ( m_pPimplData ) - delete m_pPimplData; -} - -// ----------------------------------------------------------------------------- - -size_t FingerprintExtractor::getToSkipMs() -{ return m_pPimplData->m_toSkipMs; } - -// ----------------------------------------------------------------------------- - -size_t FingerprintExtractor::getMinimumDurationMs() -{ - return static_cast( (QUERY_SIZE_SECS + NORMALIZATION_SKIP_SECS * 2 + GUARD_SIZE_SECS) * 1000 ); -} - -// ----------------------------------------------------------------------------- - -size_t FingerprintExtractor::getVersion() -{ return FINGERPRINT_LIB_VERSION; } - -// ----------------------------------------------------------------------------- - -void FingerprintExtractor::initForQuery(int freq, int nchannels, int duration ) -{ - m_pPimplData->m_skipPassed = false; - m_pPimplData->m_processType = PT_FOR_QUERY; - - if ( !m_pPimplData ) - throw std::runtime_error("Not enough RAM to allocate the fingerprinter!"); - - initCustom( *m_pPimplData, - freq, nchannels, - static_cast(QUERY_SIZE_SECS * 1000), - static_cast(QUERY_START_SECS * 1000), - MIN_UNIQUE_KEYS, - static_cast(UPDATE_SIZE_SECS * 1000), duration ); -} - -// ----------------------------------------------------------------------------- - -void FingerprintExtractor::initForFullSubmit(int freq, int nchannels ) -{ - m_pPimplData->m_skipPassed = true; - m_pPimplData->m_processType = PT_FOR_FULLSUBMIT; - - if ( !m_pPimplData ) - throw std::runtime_error("Not enough RAM to allocate the fingerprinter!"); - - initCustom( *m_pPimplData, - freq, nchannels, - numeric_limits::max(), - 0, MIN_UNIQUE_KEYS, 0, -1 ); -} - -// ----------------------------------------------------------------------------- - -void initCustom( PimplData& pd, - int freq, int nchannels, - unsigned int lengthMs, - unsigned int skipMs, - int minUniqueKeys, - unsigned int uniqueKeyWindowMs, int duration ) -{ - ////////////////////////////////////////////////////////////////////////// - pd.m_freq = freq; - pd.m_nchannels = nchannels; - pd.m_lengthMs = lengthMs; - pd.m_minUniqueKeys = minUniqueKeys; - pd.m_uniqueKeyWindowMs = uniqueKeyWindowMs; - ////////////////////////////////////////////////////////////////////////// - - // *********************************************************************** - if ( pd.m_pDownsampleState ) - pd.m_pDownsampleState = src_delete(pd.m_pDownsampleState) ; - pd.m_pDownsampleState = src_new (SRC_SINC_FASTEST, 1, NULL) ; - pd.m_downsampleData.src_ratio = FDFREQ / freq; - // *********************************************************************** - - ////////////////////////////////////////////////////////////////////////// - if ( pd.m_processType == PT_FOR_FULLSUBMIT ) - skipMs = 0; // make sure - else if ( duration > 0 ) - { - // skip + size + right normalization window + FFT guard - // - int stdDurationMs = static_cast((QUERY_START_SECS + QUERY_SIZE_SECS + NORMALIZATION_SKIP_SECS + GUARD_SIZE_SECS) * 1000); - int actualDurationMs = duration * 1000; - // compute the actual skipMs depending on the duration - if ( actualDurationMs < stdDurationMs ) - skipMs -= max( stdDurationMs - actualDurationMs, 0 ); - } - - pd.m_toSkipMs = max( static_cast(skipMs) - static_cast((pd.m_normalizedWindowMs/2)), 0 ); - pd.m_toSkipSize = static_cast( freq * nchannels * - (pd.m_toSkipMs / 1000.0) ); // half the norm window in secs; - - //if ( pd.m_processType == PT_FOR_QUERY && skipMs > pd.m_normalizedWindowMs/2 ) - //{ - // pd.m_toSkipMs = skipMs - (pd.m_normalizedWindowMs/2); - // pd.m_toSkipSize = static_cast( freq * nchannels * - // (pd.m_toSkipMs / 1000.0) ); // half the norm window in secs - //} - //else - //{ - // pd.m_toSkipMs = 0; - // pd.m_toSkipSize = 0; // half of the normalization window will be skipped in ANY case - //} - - pd.m_skippedSoFar = 0; - pd.m_groupsReady = false; - pd.m_preBufferPassed = false; - - // prepare the position for pre-buffering - pd.m_pDownsampledCurrIt = pd.m_pDownsampledPCM + (pd.m_downsampledProcessSize - (pd.m_normWindow.size() / 2) ); - - pd.m_toProcessKeys = fingerprint::getTotalKeys(pd.m_lengthMs);// (m_lengthMs * DFREQ) / (1000 * OVERLAPSAMPLES) + 1; - pd.m_totalWindowKeys = fingerprint::getTotalKeys(pd.m_uniqueKeyWindowMs); //(m_uniqueKeyWindowMs * DFREQ) / (1000 * OVERLAPSAMPLES) + 1; - - if (pd.m_toProcessKeys == 1) - pd.m_toProcessKeys = 0; - if (pd.m_totalWindowKeys == 1) - pd.m_totalWindowKeys = 0; - - pd.m_processedKeys = 0; - - pd.m_groupWindow.clear(); - pd.m_processedKeys = 0; -} - -// ----------------------------------------------------------------------------- - - -// * cb = compensate buffer size -// * norm = floating normalization window size -// -// PREBUFFER: -// (-------m_bufferSize-------) -// || EMPTY |---norm/2---|-cb-|---norm/2---|| -// 1. {--------read frames-----------} -// 2. {--read normalize window--} -// 3. {----} normalize -// -// 1. read [norm + cb] frames to m_bufferSize - norm/2 -// 2. read [m_buffersize - norm/2...m_buffersize + norm/2] into normalize window -// 3. normalize [m_bufferSize..m_bufferSize+cb] -// -// PROCESS: -// -// ||-------m_bufferSize-------|-cb-|---norm/2---|| -// 1. <--------------------------{------copy-------} -// 2. {--------read frames-------} -// 3. {---------normalize--------} -// 4. {------fft/process/whatevs------} -// -// 1. copy [m_bufferSize..m_bufferSize + cb + norm/2] to beginning -// 2. read m_bufferSize frames to cb + norm/2 -// 3. normalize [cb..m_bufferSize+cb] -// 4. fft/process/whatevs [0...m_bufferSize+cb] -// -// repeat until enough blocks processed and enough groups! -// -bool FingerprintExtractor::process( const short* pPCM, size_t num_samples, bool end_of_stream ) -{ - if ( num_samples == 0 ) - return false; - - // easier read - PimplData& pd = *m_pPimplData; - - if ( pd.m_processType == PT_UNKNOWN ) - throw std::runtime_error("Please call initForQuery() or initForFullSubmit() before process()!"); - - const short* pSourcePCMIt = pPCM; - const short* pSourcePCMIt_end = pPCM + num_samples; - - if ( !pd.m_skipPassed ) - { - // needs to skip data? (reminder: the query needs to skip QUERY_START_SECS (- half of the normalization window) - if ( pd.m_skippedSoFar + num_samples > pd.m_toSkipSize ) - { - pSourcePCMIt = pPCM + (pd.m_toSkipSize - pd.m_skippedSoFar); - pd.m_skipPassed = true; - } - else - { - // need more data - pd.m_skippedSoFar += num_samples; - return false; - } - } - - pair readData(0,0); - pd.m_downsampleData.end_of_input = end_of_stream ? 1 : 0; - - ////////////////////////////////////////////////////////////////////////// - // PREBUFFER: - if ( !pd.m_preBufferPassed ) - { - // 1. downsample [norm + cb] frames to m_bufferSize - norm/2 - pd.m_floatInData.resize( (pSourcePCMIt_end - pSourcePCMIt) / pd.m_nchannels); - src_short_to_float_and_mono_array( pSourcePCMIt, - &(pd.m_floatInData[0]), static_cast(pSourcePCMIt_end - pSourcePCMIt), - pd.m_nchannels); - - pd.m_downsampleData.data_in = &(pd.m_floatInData[0]); - pd.m_downsampleData.input_frames = static_cast(pd.m_floatInData.size()); - - pd.m_downsampleData.data_out = pd.m_pDownsampledCurrIt; - pd.m_downsampleData.output_frames = static_cast(pd.m_pEndDownsampledBuf - pd.m_pDownsampledCurrIt); - - int err = src_process(pd.m_pDownsampleState, &(pd.m_downsampleData)); - if ( err ) - throw std::runtime_error( src_strerror(err) ); - - pd.m_pDownsampledCurrIt += pd.m_downsampleData.output_frames_gen; - - if ( pd.m_pDownsampledCurrIt != pd.m_pEndDownsampledBuf ) - return false; // NEED MORE DATA - - pSourcePCMIt += pd.m_downsampleData.input_frames_used * pd.m_nchannels; - - size_t pos = pd.m_downsampledProcessSize; - size_t window_pos = pd.m_downsampledProcessSize - pd.m_normWindow.size() / 2; - const size_t end_window_pos = window_pos + pd.m_normWindow.size(); - - // 2. read [m_buffersize - norm/2...m_buffersize + norm/2] into normalize window - for (; window_pos < end_window_pos ; ++window_pos) - pd.m_normWindow.add(pd.m_pDownsampledPCM[window_pos] * pd.m_pDownsampledPCM[window_pos]); - - // 3. normalize [m_bufferSize..m_bufferSize+cb] - for (; pos < pd.m_downsampledProcessSize + pd.m_compensateBufferSize; ++pos, ++window_pos) - { - pd.m_pDownsampledPCM[pos] /= getRMS(pd.m_normWindow); - pd.m_normWindow.add(pd.m_pDownsampledPCM[window_pos] * pd.m_pDownsampledPCM[window_pos]); - } - - pd.m_preBufferPassed = true; - } - - ////////////////////////////////////////////////////////////////////////// - // PROCESS: - - bool found_enough_unique_keys = false; - while (pd.m_toProcessKeys == 0 || pd.m_processedKeys < pd.m_toProcessKeys || !found_enough_unique_keys) - { - - // 1. copy [m_bufferSize..m_bufferSize + cb + norm/2] to beginning - if ( pd.m_pDownsampledCurrIt == pd.m_pEndDownsampledBuf ) - { - memcpy( pd.m_pDownsampledPCM, pd.m_pDownsampledPCM + pd.m_downsampledProcessSize, - (pd.m_compensateBufferSize + (pd.m_normWindow.size() / 2)) * sizeof(float)); - pd.m_pDownsampledCurrIt = pd.m_pDownsampledPCM + (pd.m_compensateBufferSize + (pd.m_normWindow.size() / 2)); - } - - // 2. read m_bufferSize frames to cb + norm/2 - pd.m_floatInData.resize( (pSourcePCMIt_end - pSourcePCMIt) / pd.m_nchannels); - - if ( pd.m_floatInData.empty() ) - return false; - - src_short_to_float_and_mono_array( pSourcePCMIt, - &(pd.m_floatInData[0]), static_cast(pSourcePCMIt_end - pSourcePCMIt), - pd.m_nchannels); - - pd.m_downsampleData.data_in = &(pd.m_floatInData[0]); - pd.m_downsampleData.input_frames = static_cast(pd.m_floatInData.size()); - - pd.m_downsampleData.data_out = pd.m_pDownsampledCurrIt; - pd.m_downsampleData.output_frames = static_cast(pd.m_pEndDownsampledBuf - pd.m_pDownsampledCurrIt); - - int err = src_process(pd.m_pDownsampleState, &(pd.m_downsampleData)); - if ( err ) - throw std::runtime_error( src_strerror(err) ); - - pd.m_pDownsampledCurrIt += pd.m_downsampleData.output_frames_gen; - - if ( pd.m_pDownsampledCurrIt != pd.m_pEndDownsampledBuf && !end_of_stream ) - return false; // NEED MORE DATA - - //pSourcePCMIt += readData.second; - pSourcePCMIt += pd.m_downsampleData.input_frames_used * pd.m_nchannels; - - // ******************************************************************** - - // 3. normalize [cb..m_bufferSize+cb] - size_t pos = static_cast(pd.m_compensateBufferSize); - size_t window_pos = static_cast(pd.m_compensateBufferSize + (pd.m_normWindow.size() / 2)); - - for(; pos < pd.m_downsampledProcessSize + pd.m_compensateBufferSize /* m_fullDownsampledBufferSize*/; ++pos, ++window_pos) - { - pd.m_pDownsampledPCM[pos] /= getRMS(pd.m_normWindow); - pd.m_normWindow.add(pd.m_pDownsampledPCM[window_pos] * pd.m_pDownsampledPCM[window_pos]); - } - - // 4. fft/process/whatevs [0...m_bufferSize+cb] - pd.m_processedKeys += processKeys(pd.m_groupWindow, pos, pd); - - // we have too many keys, now we have to chop either one end or the other - if (pd.m_toProcessKeys != 0 && pd.m_processedKeys > pd.m_toProcessKeys) - { - // set up window begin and end - deque::iterator itBeg = pd.m_groupWindow.begin(), itEnd = pd.m_groupWindow.end(); - unsigned int offset_left, offset_right; - - found_enough_unique_keys = - fingerprint::findSignificantGroups( itBeg, itEnd, offset_left, offset_right, pd.m_toProcessKeys, - pd.m_totalWindowKeys, pd.m_minUniqueKeys); - - // if we're happy with this set, snip the beginning and end of the grouped keys - if (found_enough_unique_keys) - { - itBeg->count -= offset_left; - if (offset_right > 0 && itEnd != pd.m_groupWindow.end()) - { - itEnd->count = offset_right; - ++itEnd; - } - } - - // chop the deque - copy(itBeg, itEnd, pd.m_groupWindow.begin()); - pd.m_groupWindow.resize(itEnd - itBeg); - - // recalc keys - pd.m_processedKeys = 0; - for (deque::const_iterator it = pd.m_groupWindow.begin(); it != pd.m_groupWindow.end(); ++it) - pd.m_processedKeys += it->count; - } - - if ( end_of_stream ) - break; - - } // while (totalKeys == 0 || keys < totalKeys || !found_enough_unique_keys) - - - if (pd.m_toProcessKeys != 0 && pd.m_processedKeys < pd.m_toProcessKeys) - throw std::runtime_error("Couldn't deliver the requested number of keys (it's the file too short?)"); - - if ((pd.m_toProcessKeys != 0 && !found_enough_unique_keys) || - (pd.m_toProcessKeys == 0 && !enoughUniqueGoodGroups(pd.m_groupWindow.begin(), pd.m_groupWindow.end(), pd.m_minUniqueKeys))) - { - throw std::runtime_error("Not enough unique keys (it's the file too short?)"); - } - - // copy to a vector so that they can be returned as contiguous data - pd.m_groups.resize(pd.m_groupWindow.size()); - copy(pd.m_groupWindow.begin(), pd.m_groupWindow.end(), pd.m_groups.begin()); - - pd.m_groupsReady = true; - pd.m_processType = PT_UNKNOWN; - return true; -} - -// ----------------------------------------------------------------------------- - -pair FingerprintExtractor::getFingerprint() -{ - // easier read - PimplData& pd = *m_pPimplData; - - if ( pd.m_groupsReady ) - { -#if __BIG_ENDIAN__ - pd.m_bigEndianGroups.resize(pd.m_groups.size()); - for ( size_t i = 0; i < pd.m_groups.size(); ++i ) - { - pd.m_bigEndianGroups[i].key = reorderbits(pd.m_groups[i].key); - pd.m_bigEndianGroups[i].count = reorderbits(pd.m_groups[i].count); - } - - return make_pair(reinterpret_cast(&pd.m_bigEndianGroups[0]), pd.m_bigEndianGroups.size() * sizeof(GroupData) ); - -#else - return make_pair(reinterpret_cast(&pd.m_groups[0]), pd.m_groups.size() * sizeof(GroupData) ); -#endif - } - else - return make_pair(reinterpret_cast(0), 0); // here's where null_ptr would become useful! -} - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- - -float getRMS(const FloatingAverage& signal) -{ - // we don't want to normalize by the real rms, because excessive clipping will occur - float rms = sqrtf(static_cast(signal.getAverage())) * 10.0F; - - if (rms < 0.1F) - rms = 0.1F; - else if (rms > 3.0F) - rms = 3.0F; - - return rms; -} - -// ----------------------------------------------------------------------------- - -unsigned int processKeys( deque& groups, size_t size, PimplData& pd ) -{ - size_t read_size = min(size, pd.m_downsampledProcessSize + pd.m_compensateBufferSize); - - unsigned int numFrames = pd.m_pFFT->process(pd.m_pDownsampledPCM, read_size); - - if ( numFrames <= Filter::KEYWIDTH ) - return 0; // skip it when the number of frames is too small - - float** ppFrames = pd.m_pFFT->getFrames(); - - integralImage(ppFrames, numFrames); - computeBits(pd.m_partialBits, pd.m_filters, ppFrames, numFrames); - fingerprint::keys2GroupData(pd.m_partialBits, groups, false); - - return static_cast(pd.m_partialBits.size()); - -} - -// ----------------------------------------------------------------------------- - -void integralImage(float** ppFrames, unsigned int nFrames) -{ - for (unsigned int y = 1; y < nFrames; y++) - { - ppFrames[y][0] += ppFrames[y-1][0]; - } - - for (unsigned int x = 1; x < Filter::NBANDS; x++) - { - ppFrames[0][x] += ppFrames[0][x-1]; - } - - for (unsigned int y = 1; y < nFrames; y++) - { - for (unsigned int x = 1; x < Filter::NBANDS; x++) - { - ppFrames[y][x] += static_cast( static_cast(ppFrames[y-1][x]) + - static_cast(ppFrames[y][x-1]) - - static_cast(ppFrames[y-1][x-1]) ); - } - } -} - -// --------------------------------------------------------------------- -// -/// Convert bands to bits, using the supplied filters -void computeBits( vector& bits, - const vector& f, - float ** frames, unsigned int nframes ) -{ - unsigned int first_time = Filter::KEYWIDTH / 2 + 1; - unsigned int last_time = nframes - Filter::KEYWIDTH / 2; - - unsigned int numBits = last_time - first_time + 1; - bits.resize(numBits); - - const unsigned int fSize = static_cast(f.size()); - std::bitset<32> bt; - double X = 0; - - for (unsigned int t2 = first_time; t2 <= last_time; ++t2) - { - - for (unsigned int i = 0; i < fSize; ++i) - { - // we subtract 1 from t1 and b1 because we use integral images - - unsigned int t1 = (unsigned int) ((float) t2 - f[i].wt / 2.0 - 1); - unsigned int t3 = (unsigned int) ((float) t2 + f[i].wt / 2.0 - 1); - unsigned int b1 = f[i].first_band; - unsigned int b2 = (unsigned int) round__((float) b1 + f[i].wb / 2.0) - 1; - unsigned int b3 = b1 + f[i].wb - 1; - --b1; - - unsigned int t_1q = (t1 + t2) / 2; // one quarter time - unsigned int t_3q = t_1q + (t3 - t1 + 1) / 2; // three quarter time - unsigned int b_1q = (b1 + b2) / 2; // one quarter band - unsigned int b_3q = b_1q + (b3 - b1) / 2; // three quarter band - - X = 0; - - // we should check from t1 > 0, but in practice, this doesn't happen - // we subtract 1 from everything because this came from matlab where indices start from 1 - switch (f[i].filter_type) { - case 1: { // total energy - if (b1 > 0) - X = static_cast(frames[t3-1][b3-1]) - static_cast(frames[t3-1][b1-1]) - - static_cast(frames[t1-1][b3-1]) + static_cast(frames[t1-1][b1-1]); - else - X = static_cast(frames[t3-1][b3-1]) - static_cast(frames[t1-1][b3-1]); - break; - } - case 2: { // energy difference over time - if (b1 > 0) - X = static_cast(frames[t1-1][b1-1]) - 2*static_cast(frames[t2-2][b1-1]) - + static_cast(frames[t3-1][b1-1]) - static_cast(frames[t1-1][b3-1]) - + 2*static_cast(frames[t2-2][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = - static_cast(frames[t1-1][b3-1]) + 2*static_cast(frames[t2-2][b3-1]) - - static_cast(frames[t3-1][b3-1]); - break; - - } - case 3: { // energy difference over bands - if (b1 > 0) - X = static_cast(frames[t1-1][b1-1]) - static_cast(frames[t3-1][b1-1]) - - 2*static_cast(frames[t1-1][b2-1]) + 2*static_cast(frames[t3-1][b2-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = - 2*static_cast(frames[t1-1][b2-1]) + 2*static_cast(frames[t3-1][b2-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - break; - } - case 4: { - // energy difference over time and bands - if (b1 > 0) - X = static_cast(frames[t1-1][b1-1]) - 2*static_cast(frames[t2-2][b1-1]) - + static_cast(frames[t3-1][b1-1]) - 2*static_cast(frames[t1-1][b2-1]) - + 4*static_cast(frames[t2-2][b2-1]) - 2*static_cast(frames[t3-1][b2-1]) - + static_cast(frames[t1-1][b3-1]) - 2*static_cast(frames[t2-2][b3-1]) - + static_cast(frames[t3-1][b3-1]); - else - X = - 2*static_cast(frames[t1-1][b2-1]) + 4*static_cast(frames[t2-2][b2-1]) - - 2*static_cast(frames[t3-1][b2-1]) + static_cast(frames[t1-1][b3-1]) - - 2*static_cast(frames[t2-2][b3-1]) + static_cast(frames[t3-1][b3-1]); - break; - } - case 5: { // time peak - if (b1 > 0) - X = - static_cast(frames[t1-1][b1-1]) + 2*static_cast(frames[t_1q-1][b1-1]) - - 2*static_cast(frames[t_3q-1][b1-1]) + static_cast(frames[t3-1][b1-1]) - + static_cast(frames[t1-1][b3-1]) - 2*static_cast(frames[t_1q-1][b3-1]) - + 2*static_cast(frames[t_3q-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = static_cast(frames[t1-1][b3-1]) - 2*static_cast(frames[t_1q-1][b3-1]) - + 2*static_cast(frames[t_3q-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - - break; - } - case 6: { // band beak - if (b1 > 0) - X = - static_cast(frames[t1-1][b1-1]) + static_cast(frames[t3-1][b1-1]) - + 2*static_cast(frames[t1-1][b_1q-1]) - 2*static_cast(frames[t3-1][b_1q-1]) - - 2*static_cast(frames[t1-1][b_3q-1]) + 2*static_cast(frames[t3-1][b_3q-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - else - X = + 2*static_cast(frames[t1-1][b_1q-1]) - 2*static_cast(frames[t3-1][b_1q-1]) - - 2*static_cast(frames[t1-1][b_3q-1]) + 2*static_cast(frames[t3-1][b_3q-1]) - + static_cast(frames[t1-1][b3-1]) - static_cast(frames[t3-1][b3-1]); - - break; - } - } - - bt[i] = X > f[i].threshold; - } - - bits[t2 - first_time] = bt.to_ulong(); - } -} - -// ----------------------------------------------------------------------------- - -void src_short_to_float_and_mono_array( const short *in, float *out, int srclen, int nchannels ) -{ - switch ( nchannels ) - { - case 1: - src_short_to_float_array(in, out, srclen); - break; - case 2: - { - // this can be optimized - int j = 0; - const double div = numeric_limits::max() * nchannels; - for ( int i = 0; i < srclen; i += 2, ++j ) - { - out[j] = static_cast( static_cast(static_cast(in[i]) + static_cast(in[i+1])) / div ); - } - } - break; - - default: - throw( std::runtime_error("Unsupported number of channels!") ); - } - -} - -// ----------------------------------------------------------------------------- - -} // end of namespace - -// ----------------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h b/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h deleted file mode 100644 index fac9b5887..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/FingerprintExtractor.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FINGERPRINT_EXTRACTOR_H -#define __FINGERPRINT_EXTRACTOR_H - -#include // for pair -#include // for size_t - -namespace fingerprint { - -// ----------------------------------------------------------------------------- - -class PimplData; - -class FingerprintExtractor -{ -public: - - FingerprintExtractor(); // ctor - ~FingerprintExtractor(); // dtor - - // duration (in seconds!) is optional, but if you want to submit tracks <34 secs - // it must be provided. - void initForQuery(int freq, int nchannels, int duration = -1); - void initForFullSubmit(int freq, int nchannels); - - // return false if it needs more data, otherwise true - // IMPORTANT: num_samples specify the size of the *short* array pPCM, that is - // the number of samples that are in the buffer. This includes - // the stereo samples, i.e. - // [L][R][L][R][L][R][L][R] would be num_samples=8 - bool process(const short* pPCM, size_t num_samples, bool end_of_stream = false); - - // returns pair if the data is not ready - std::pair getFingerprint(); - - ////////////////////////////////////////////////////////////////////////// - - // The FingerprintExtractor assumes that the file start from the beginning - // but since the first SkipMs are ignored, it's possible to feed it with NULL. - // In order to know how much must be skipped (in milliseconds) call this function. - // Remark: this is only for "advanced" users! - size_t getToSkipMs(); - - // Return the minimum duration of the file (in ms) - // Any file with a length smaller than this value will be discarded - static size_t getMinimumDurationMs(); - - // return the version of the fingerprint - static size_t getVersion(); - -private: - - PimplData* m_pPimplData; -}; - -// ----------------------------------------------------------------------------- - -} // end of namespace fingerprint - -#endif // __FINGERPRINT_EXTRACTOR_H diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h b/thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h deleted file mode 100644 index 1be665bd0..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/FloatingAverage.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FLOAT_AVERAGE_H__ -#define __FLOAT_AVERAGE_H__ - -//#include -#include -#include "CircularArray.h" - -template -class FloatingAverage -{ -public: - FloatingAverage(size_t size) - { - m_values.resize(size); - m_valIt = m_values.head(); - m_sum = 0; - m_bufferFilled = false; - } - - void purge() - { - m_sum = 0; - const T* pCircularBuffer = m_values.get_buffer(); - const int size = m_values.size(); - - for ( int i = 0; i < size; ++i ) - m_sum += pCircularBuffer[i]; - } - - void add(const T& value) - { - m_sum += value; - - if ( m_bufferFilled ) - { - m_sum -= *m_valIt; - *m_valIt = value; - ++m_valIt; - } - else - { - *m_valIt = value; - ++m_valIt; - if ( m_valIt == m_values.head() ) - m_bufferFilled = true; - } - } - - T getAverage() const - { - if ( !m_bufferFilled ) - return m_sum / (m_valIt - m_values.head()); - else - return m_sum / m_values.size(); - } - - T getError() const - { - T real_sum = 0; - const T* pCircularBuffer = m_values.get_buffer(); - for ( int i = 0; i < size; ++i ) - real_sum += pCircularBuffer[i]; - return abs(real_sum - m_sum) / this->size(); - } - - size_t size() const - { - return m_values.size(); - } - - void clear() - { - m_bufferFilled = false; - m_values.zero_fill(); - m_valIt = m_values.head(); - m_sum = 0; - } - -private: - //std::deque m_values; - CircularArray m_values; - typename CircularArray::iterator m_valIt; - - bool m_bufferFilled; - T m_sum; -}; - -#endif // __FLOAT_AVERAGE_H__ diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp b/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp deleted file mode 100644 index 3728c974c..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "OptFFT.h" -#include "fp_helper_fun.h" -#include "Filter.h" // for NBANDS - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -// ---------------------------------------------------------------------- - -namespace fingerprint -{ - - static const float hann[] = { - 0.000000f,0.000002f,0.000009f,0.000021f,0.000038f,0.000059f,0.000085f,0.000115f,0.000151f,0.000191f,0.000236f, - 0.000285f,0.000339f,0.000398f,0.000462f,0.000530f,0.000603f,0.000681f,0.000763f,0.000850f,0.000942f,0.001038f, - 0.001140f,0.001245f,0.001356f,0.001471f,0.001591f,0.001716f,0.001845f,0.001980f,0.002118f,0.002262f,0.002410f, - 0.002563f,0.002720f,0.002883f,0.003049f,0.003221f,0.003397f,0.003578f,0.003764f,0.003954f,0.004149f,0.004349f, - 0.004553f,0.004762f,0.004976f,0.005194f,0.005417f,0.005645f,0.005877f,0.006114f,0.006355f,0.006602f,0.006853f, - 0.007108f,0.007368f,0.007633f,0.007903f,0.008177f,0.008455f,0.008739f,0.009027f,0.009319f,0.009617f,0.009919f, - 0.010225f,0.010536f,0.010852f,0.011172f,0.011497f,0.011827f,0.012161f,0.012499f,0.012843f,0.013191f,0.013543f, - 0.013900f,0.014262f,0.014628f,0.014999f,0.015374f,0.015754f,0.016139f,0.016528f,0.016921f,0.017320f,0.017722f, - 0.018130f,0.018541f,0.018958f,0.019379f,0.019804f,0.020234f,0.020668f,0.021107f,0.021551f,0.021999f,0.022451f, - 0.022908f,0.023370f,0.023836f,0.024306f,0.024781f,0.025260f,0.025744f,0.026233f,0.026725f,0.027223f,0.027724f, - 0.028231f,0.028741f,0.029256f,0.029776f,0.030300f,0.030828f,0.031361f,0.031898f,0.032440f,0.032986f,0.033536f, - 0.034091f,0.034650f,0.035214f,0.035781f,0.036354f,0.036930f,0.037512f,0.038097f,0.038687f,0.039281f,0.039879f, - 0.040482f,0.041089f,0.041701f,0.042316f,0.042936f,0.043561f,0.044189f,0.044822f,0.045460f,0.046101f,0.046747f, - 0.047397f,0.048052f,0.048710f,0.049373f,0.050040f,0.050711f,0.051387f,0.052067f,0.052751f,0.053439f,0.054132f, - 0.054828f,0.055529f,0.056234f,0.056943f,0.057657f,0.058374f,0.059096f,0.059822f,0.060552f,0.061286f,0.062024f, - 0.062767f,0.063513f,0.064264f,0.065019f,0.065777f,0.066540f,0.067307f,0.068078f,0.068854f,0.069633f,0.070416f, - 0.071204f,0.071995f,0.072790f,0.073590f,0.074393f,0.075201f,0.076012f,0.076828f,0.077647f,0.078470f,0.079298f, - 0.080129f,0.080964f,0.081804f,0.082647f,0.083494f,0.084345f,0.085200f,0.086059f,0.086922f,0.087788f,0.088659f, - 0.089533f,0.090412f,0.091294f,0.092180f,0.093070f,0.093963f,0.094861f,0.095762f,0.096667f,0.097576f,0.098489f, - 0.099406f,0.100326f,0.101250f,0.102178f,0.103109f,0.104045f,0.104984f,0.105926f,0.106873f,0.107823f,0.108777f, - 0.109734f,0.110696f,0.111661f,0.112629f,0.113601f,0.114577f,0.115557f,0.116540f,0.117526f,0.118517f,0.119511f, - 0.120508f,0.121509f,0.122514f,0.123522f,0.124534f,0.125549f,0.126568f,0.127590f,0.128616f,0.129645f,0.130678f, - 0.131714f,0.132754f,0.133797f,0.134844f,0.135894f,0.136948f,0.138005f,0.139065f,0.140129f,0.141196f,0.142266f, - 0.143340f,0.144418f,0.145498f,0.146582f,0.147670f,0.148760f,0.149854f,0.150951f,0.152052f,0.153156f,0.154263f, - 0.155373f,0.156487f,0.157603f,0.158723f,0.159847f,0.160973f,0.162103f,0.163236f,0.164372f,0.165511f,0.166653f, - 0.167799f,0.168947f,0.170099f,0.171254f,0.172411f,0.173572f,0.174737f,0.175904f,0.177074f,0.178247f,0.179423f, - 0.180603f,0.181785f,0.182970f,0.184158f,0.185350f,0.186544f,0.187741f,0.188941f,0.190144f,0.191350f,0.192559f, - 0.193771f,0.194986f,0.196203f,0.197423f,0.198647f,0.199873f,0.201102f,0.202333f,0.203568f,0.204805f,0.206045f, - 0.207288f,0.208534f,0.209782f,0.211033f,0.212287f,0.213544f,0.214803f,0.216065f,0.217329f,0.218597f,0.219867f, - 0.221139f,0.222414f,0.223692f,0.224972f,0.226255f,0.227541f,0.228829f,0.230120f,0.231413f,0.232709f,0.234007f, - 0.235308f,0.236611f,0.237917f,0.239225f,0.240536f,0.241849f,0.243165f,0.244483f,0.245803f,0.247126f,0.248451f, - 0.249779f,0.251108f,0.252441f,0.253775f,0.255112f,0.256451f,0.257793f,0.259137f,0.260483f,0.261831f,0.263182f, - 0.264534f,0.265889f,0.267247f,0.268606f,0.269967f,0.271331f,0.272697f,0.274065f,0.275435f,0.276808f,0.278182f, - 0.279558f,0.280937f,0.282318f,0.283700f,0.285085f,0.286472f,0.287861f,0.289251f,0.290644f,0.292039f,0.293435f, - 0.294834f,0.296235f,0.297637f,0.299041f,0.300448f,0.301856f,0.303266f,0.304678f,0.306091f,0.307507f,0.308924f, - 0.310343f,0.311764f,0.313187f,0.314611f,0.316038f,0.317466f,0.318895f,0.320327f,0.321760f,0.323194f,0.324631f, - 0.326069f,0.327509f,0.328950f,0.330393f,0.331837f,0.333283f,0.334731f,0.336180f,0.337631f,0.339083f,0.340537f, - 0.341993f,0.343449f,0.344908f,0.346368f,0.347829f,0.349291f,0.350755f,0.352221f,0.353688f,0.355156f,0.356626f, - 0.358097f,0.359569f,0.361042f,0.362517f,0.363994f,0.365471f,0.366950f,0.368430f,0.369911f,0.371394f,0.372877f, - 0.374362f,0.375848f,0.377336f,0.378824f,0.380314f,0.381804f,0.383296f,0.384789f,0.386283f,0.387778f,0.389274f, - 0.390771f,0.392269f,0.393768f,0.395269f,0.396770f,0.398272f,0.399775f,0.401279f,0.402784f,0.404290f,0.405797f, - 0.407305f,0.408813f,0.410322f,0.411833f,0.413344f,0.414856f,0.416368f,0.417882f,0.419396f,0.420911f,0.422427f, - 0.423944f,0.425461f,0.426979f,0.428497f,0.430017f,0.431537f,0.433057f,0.434578f,0.436100f,0.437623f,0.439146f, - 0.440669f,0.442193f,0.443718f,0.445243f,0.446769f,0.448295f,0.449822f,0.451349f,0.452877f,0.454405f,0.455934f, - 0.457463f,0.458992f,0.460522f,0.462052f,0.463582f,0.465113f,0.466644f,0.468176f,0.469708f,0.471240f,0.472772f, - 0.474305f,0.475837f,0.477370f,0.478904f,0.480437f,0.481971f,0.483505f,0.485039f,0.486573f,0.488107f,0.489641f, - 0.491176f,0.492710f,0.494245f,0.495780f,0.497314f,0.498849f,0.500384f,0.501918f,0.503453f,0.504988f,0.506522f, - 0.508057f,0.509591f,0.511126f,0.512660f,0.514194f,0.515728f,0.517262f,0.518796f,0.520330f,0.521863f,0.523396f, - 0.524929f,0.526462f,0.527994f,0.529526f,0.531058f,0.532590f,0.534121f,0.535652f,0.537183f,0.538713f,0.540243f, - 0.541773f,0.543302f,0.544831f,0.546359f,0.547887f,0.549414f,0.550941f,0.552468f,0.553994f,0.555519f,0.557044f, - 0.558569f,0.560093f,0.561616f,0.563139f,0.564661f,0.566182f,0.567703f,0.569223f,0.570743f,0.572262f,0.573780f, - 0.575298f,0.576815f,0.578331f,0.579846f,0.581361f,0.582875f,0.584388f,0.585900f,0.587412f,0.588922f,0.590432f, - 0.591941f,0.593449f,0.594957f,0.596463f,0.597968f,0.599473f,0.600977f,0.602479f,0.603981f,0.605482f,0.606981f, - 0.608480f,0.609978f,0.611474f,0.612970f,0.614464f,0.615958f,0.617450f,0.618941f,0.620431f,0.621920f,0.623408f, - 0.624895f,0.626380f,0.627865f,0.629348f,0.630830f,0.632310f,0.633790f,0.635268f,0.636745f,0.638220f,0.639695f, - 0.641167f,0.642639f,0.644109f,0.645578f,0.647046f,0.648512f,0.649977f,0.651440f,0.652902f,0.654363f,0.655822f, - 0.657279f,0.658735f,0.660190f,0.661643f,0.663094f,0.664544f,0.665993f,0.667440f,0.668885f,0.670329f,0.671771f, - 0.673212f,0.674650f,0.676088f,0.677523f,0.678957f,0.680389f,0.681820f,0.683249f,0.684676f,0.686101f,0.687525f, - 0.688946f,0.690366f,0.691785f,0.693201f,0.694616f,0.696029f,0.697439f,0.698849f,0.700256f,0.701661f,0.703065f, - 0.704466f,0.705866f,0.707263f,0.708659f,0.710053f,0.711444f,0.712834f,0.714222f,0.715608f,0.716991f,0.718373f, - 0.719752f,0.721130f,0.722505f,0.723879f,0.725250f,0.726619f,0.727986f,0.729351f,0.730714f,0.732074f,0.733432f, - 0.734788f,0.736142f,0.737494f,0.738843f,0.740191f,0.741536f,0.742878f,0.744219f,0.745557f,0.746892f,0.748226f, - 0.749557f,0.750886f,0.752212f,0.753536f,0.754857f,0.756177f,0.757493f,0.758808f,0.760120f,0.761429f,0.762736f, - 0.764041f,0.765343f,0.766642f,0.767939f,0.769234f,0.770526f,0.771815f,0.773102f,0.774386f,0.775668f,0.776947f, - 0.778224f,0.779497f,0.780769f,0.782037f,0.783303f,0.784567f,0.785827f,0.787085f,0.788340f,0.789593f,0.790842f, - 0.792089f,0.793334f,0.794575f,0.795814f,0.797050f,0.798283f,0.799513f,0.800741f,0.801965f,0.803187f,0.804406f, - 0.805622f,0.806835f,0.808046f,0.809253f,0.810458f,0.811659f,0.812858f,0.814054f,0.815246f,0.816436f,0.817623f, - 0.818807f,0.819987f,0.821165f,0.822340f,0.823512f,0.824680f,0.825846f,0.827008f,0.828168f,0.829324f,0.830477f, - 0.831628f,0.832775f,0.833918f,0.835059f,0.836197f,0.837331f,0.838462f,0.839591f,0.840715f,0.841837f,0.842955f, - 0.844071f,0.845183f,0.846291f,0.847397f,0.848499f,0.849598f,0.850693f,0.851786f,0.852874f,0.853960f,0.855042f, - 0.856121f,0.857197f,0.858269f,0.859338f,0.860404f,0.861466f,0.862524f,0.863580f,0.864631f,0.865680f,0.866725f, - 0.867766f,0.868804f,0.869839f,0.870870f,0.871897f,0.872922f,0.873942f,0.874959f,0.875973f,0.876983f,0.877989f, - 0.878992f,0.879991f,0.880987f,0.881979f,0.882967f,0.883952f,0.884934f,0.885911f,0.886885f,0.887856f,0.888822f, - 0.889785f,0.890745f,0.891701f,0.892653f,0.893601f,0.894545f,0.895486f,0.896423f,0.897357f,0.898287f,0.899213f, - 0.900135f,0.901053f,0.901968f,0.902879f,0.903786f,0.904689f,0.905588f,0.906484f,0.907376f,0.908264f,0.909148f, - 0.910028f,0.910904f,0.911777f,0.912645f,0.913510f,0.914371f,0.915228f,0.916081f,0.916930f,0.917775f,0.918616f, - 0.919454f,0.920287f,0.921116f,0.921942f,0.922763f,0.923581f,0.924394f,0.925204f,0.926009f,0.926810f,0.927608f, - 0.928401f,0.929191f,0.929976f,0.930757f,0.931534f,0.932308f,0.933077f,0.933842f,0.934603f,0.935359f,0.936112f, - 0.936861f,0.937605f,0.938345f,0.939082f,0.939814f,0.940542f,0.941265f,0.941985f,0.942701f,0.943412f,0.944119f, - 0.944822f,0.945521f,0.946215f,0.946906f,0.947592f,0.948274f,0.948951f,0.949625f,0.950294f,0.950959f,0.951620f, - 0.952276f,0.952928f,0.953576f,0.954220f,0.954859f,0.955495f,0.956125f,0.956752f,0.957374f,0.957992f,0.958606f, - 0.959215f,0.959820f,0.960420f,0.961017f,0.961609f,0.962196f,0.962780f,0.963358f,0.963933f,0.964503f,0.965069f, - 0.965630f,0.966187f,0.966740f,0.967288f,0.967832f,0.968371f,0.968906f,0.969437f,0.969963f,0.970485f,0.971002f, - 0.971515f,0.972023f,0.972527f,0.973027f,0.973522f,0.974012f,0.974498f,0.974980f,0.975457f,0.975930f,0.976398f, - 0.976862f,0.977321f,0.977776f,0.978226f,0.978672f,0.979113f,0.979549f,0.979982f,0.980409f,0.980832f,0.981251f, - 0.981665f,0.982075f,0.982480f,0.982880f,0.983276f,0.983667f,0.984054f,0.984436f,0.984814f,0.985187f,0.985556f, - 0.985919f,0.986279f,0.986634f,0.986984f,0.987329f,0.987670f,0.988007f,0.988339f,0.988666f,0.988989f,0.989307f, - 0.989620f,0.989929f,0.990233f,0.990532f,0.990827f,0.991118f,0.991403f,0.991684f,0.991961f,0.992233f,0.992500f, - 0.992762f,0.993020f,0.993273f,0.993522f,0.993766f,0.994005f,0.994240f,0.994470f,0.994695f,0.994916f,0.995132f, - 0.995343f,0.995550f,0.995752f,0.995949f,0.996142f,0.996329f,0.996513f,0.996691f,0.996865f,0.997035f,0.997199f, - 0.997359f,0.997514f,0.997665f,0.997810f,0.997952f,0.998088f,0.998220f,0.998347f,0.998469f,0.998587f,0.998700f, - 0.998808f,0.998912f,0.999010f,0.999105f,0.999194f,0.999279f,0.999359f,0.999434f,0.999505f,0.999571f,0.999632f, - 0.999689f,0.999740f,0.999787f,0.999830f,0.999868f,0.999900f,0.999929f,0.999952f,0.999971f,0.999985f,0.999995f, - 0.999999f,0.999999f,0.999995f,0.999985f,0.999971f,0.999952f,0.999929f,0.999900f,0.999868f,0.999830f,0.999787f, - 0.999740f,0.999689f,0.999632f,0.999571f,0.999505f,0.999434f,0.999359f,0.999279f,0.999194f,0.999105f,0.999010f, - 0.998912f,0.998808f,0.998700f,0.998587f,0.998469f,0.998347f,0.998220f,0.998088f,0.997952f,0.997810f,0.997665f, - 0.997514f,0.997359f,0.997199f,0.997035f,0.996865f,0.996691f,0.996513f,0.996329f,0.996142f,0.995949f,0.995752f, - 0.995550f,0.995343f,0.995132f,0.994916f,0.994695f,0.994470f,0.994240f,0.994005f,0.993766f,0.993522f,0.993273f, - 0.993020f,0.992762f,0.992500f,0.992233f,0.991961f,0.991684f,0.991403f,0.991118f,0.990827f,0.990532f,0.990233f, - 0.989929f,0.989620f,0.989307f,0.988989f,0.988666f,0.988339f,0.988007f,0.987670f,0.987329f,0.986984f,0.986634f, - 0.986279f,0.985919f,0.985556f,0.985187f,0.984814f,0.984436f,0.984054f,0.983667f,0.983276f,0.982880f,0.982480f, - 0.982075f,0.981665f,0.981251f,0.980832f,0.980409f,0.979982f,0.979549f,0.979113f,0.978672f,0.978226f,0.977776f, - 0.977321f,0.976862f,0.976398f,0.975930f,0.975457f,0.974980f,0.974498f,0.974012f,0.973522f,0.973027f,0.972527f, - 0.972023f,0.971515f,0.971002f,0.970485f,0.969963f,0.969437f,0.968906f,0.968371f,0.967832f,0.967288f,0.966740f, - 0.966187f,0.965630f,0.965069f,0.964503f,0.963933f,0.963358f,0.962780f,0.962196f,0.961609f,0.961017f,0.960420f, - 0.959820f,0.959215f,0.958606f,0.957992f,0.957374f,0.956752f,0.956125f,0.955495f,0.954859f,0.954220f,0.953576f, - 0.952928f,0.952276f,0.951620f,0.950959f,0.950294f,0.949625f,0.948951f,0.948274f,0.947592f,0.946906f,0.946215f, - 0.945521f,0.944822f,0.944119f,0.943412f,0.942701f,0.941985f,0.941265f,0.940542f,0.939814f,0.939082f,0.938345f, - 0.937605f,0.936861f,0.936112f,0.935359f,0.934603f,0.933842f,0.933077f,0.932308f,0.931534f,0.930757f,0.929976f, - 0.929191f,0.928401f,0.927608f,0.926810f,0.926009f,0.925204f,0.924394f,0.923581f,0.922763f,0.921942f,0.921116f, - 0.920287f,0.919454f,0.918616f,0.917775f,0.916930f,0.916081f,0.915228f,0.914371f,0.913510f,0.912645f,0.911777f, - 0.910904f,0.910028f,0.909148f,0.908264f,0.907376f,0.906484f,0.905588f,0.904689f,0.903786f,0.902879f,0.901968f, - 0.901053f,0.900135f,0.899213f,0.898287f,0.897357f,0.896423f,0.895486f,0.894545f,0.893601f,0.892653f,0.891701f, - 0.890745f,0.889785f,0.888822f,0.887856f,0.886885f,0.885911f,0.884934f,0.883952f,0.882967f,0.881979f,0.880987f, - 0.879991f,0.878992f,0.877989f,0.876983f,0.875973f,0.874959f,0.873942f,0.872922f,0.871897f,0.870870f,0.869839f, - 0.868804f,0.867766f,0.866725f,0.865680f,0.864631f,0.863580f,0.862524f,0.861466f,0.860404f,0.859338f,0.858269f, - 0.857197f,0.856121f,0.855042f,0.853960f,0.852874f,0.851786f,0.850693f,0.849598f,0.848499f,0.847397f,0.846291f, - 0.845183f,0.844071f,0.842955f,0.841837f,0.840715f,0.839591f,0.838462f,0.837331f,0.836197f,0.835059f,0.833918f, - 0.832775f,0.831628f,0.830477f,0.829324f,0.828168f,0.827008f,0.825846f,0.824680f,0.823512f,0.822340f,0.821165f, - 0.819987f,0.818807f,0.817623f,0.816436f,0.815246f,0.814054f,0.812858f,0.811659f,0.810458f,0.809253f,0.808046f, - 0.806835f,0.805622f,0.804406f,0.803187f,0.801965f,0.800741f,0.799513f,0.798283f,0.797050f,0.795814f,0.794575f, - 0.793334f,0.792089f,0.790842f,0.789593f,0.788340f,0.787085f,0.785827f,0.784567f,0.783303f,0.782037f,0.780769f, - 0.779497f,0.778224f,0.776947f,0.775668f,0.774386f,0.773102f,0.771815f,0.770526f,0.769234f,0.767939f,0.766642f, - 0.765343f,0.764041f,0.762736f,0.761429f,0.760120f,0.758808f,0.757493f,0.756177f,0.754857f,0.753536f,0.752212f, - 0.750886f,0.749557f,0.748226f,0.746892f,0.745557f,0.744219f,0.742878f,0.741536f,0.740191f,0.738843f,0.737494f, - 0.736142f,0.734788f,0.733432f,0.732074f,0.730714f,0.729351f,0.727986f,0.726619f,0.725250f,0.723879f,0.722505f, - 0.721130f,0.719752f,0.718373f,0.716991f,0.715608f,0.714222f,0.712834f,0.711444f,0.710053f,0.708659f,0.707263f, - 0.705866f,0.704466f,0.703065f,0.701661f,0.700256f,0.698849f,0.697439f,0.696029f,0.694616f,0.693201f,0.691785f, - 0.690366f,0.688946f,0.687525f,0.686101f,0.684676f,0.683249f,0.681820f,0.680389f,0.678957f,0.677523f,0.676088f, - 0.674650f,0.673212f,0.671771f,0.670329f,0.668885f,0.667440f,0.665993f,0.664544f,0.663094f,0.661643f,0.660190f, - 0.658735f,0.657279f,0.655822f,0.654363f,0.652902f,0.651440f,0.649977f,0.648512f,0.647046f,0.645578f,0.644109f, - 0.642639f,0.641167f,0.639695f,0.638220f,0.636745f,0.635268f,0.633790f,0.632310f,0.630830f,0.629348f,0.627865f, - 0.626380f,0.624895f,0.623408f,0.621920f,0.620431f,0.618941f,0.617450f,0.615958f,0.614464f,0.612970f,0.611474f, - 0.609978f,0.608480f,0.606981f,0.605482f,0.603981f,0.602479f,0.600977f,0.599473f,0.597968f,0.596463f,0.594957f, - 0.593449f,0.591941f,0.590432f,0.588922f,0.587412f,0.585900f,0.584388f,0.582875f,0.581361f,0.579846f,0.578331f, - 0.576815f,0.575298f,0.573780f,0.572262f,0.570743f,0.569223f,0.567703f,0.566182f,0.564661f,0.563139f,0.561616f, - 0.560093f,0.558569f,0.557044f,0.555519f,0.553994f,0.552468f,0.550941f,0.549414f,0.547887f,0.546359f,0.544831f, - 0.543302f,0.541773f,0.540243f,0.538713f,0.537183f,0.535652f,0.534121f,0.532590f,0.531058f,0.529526f,0.527994f, - 0.526462f,0.524929f,0.523396f,0.521863f,0.520330f,0.518796f,0.517262f,0.515728f,0.514194f,0.512660f,0.511126f, - 0.509591f,0.508057f,0.506522f,0.504988f,0.503453f,0.501918f,0.500384f,0.498849f,0.497314f,0.495780f,0.494245f, - 0.492710f,0.491176f,0.489641f,0.488107f,0.486573f,0.485039f,0.483505f,0.481971f,0.480437f,0.478904f,0.477370f, - 0.475837f,0.474305f,0.472772f,0.471240f,0.469708f,0.468176f,0.466644f,0.465113f,0.463582f,0.462052f,0.460522f, - 0.458992f,0.457463f,0.455934f,0.454405f,0.452877f,0.451349f,0.449822f,0.448295f,0.446769f,0.445243f,0.443718f, - 0.442193f,0.440669f,0.439146f,0.437623f,0.436100f,0.434578f,0.433057f,0.431537f,0.430017f,0.428497f,0.426979f, - 0.425461f,0.423944f,0.422427f,0.420911f,0.419396f,0.417882f,0.416368f,0.414856f,0.413344f,0.411833f,0.410322f, - 0.408813f,0.407305f,0.405797f,0.404290f,0.402784f,0.401279f,0.399775f,0.398272f,0.396770f,0.395269f,0.393768f, - 0.392269f,0.390771f,0.389274f,0.387778f,0.386283f,0.384789f,0.383296f,0.381804f,0.380314f,0.378824f,0.377336f, - 0.375848f,0.374362f,0.372877f,0.371394f,0.369911f,0.368430f,0.366950f,0.365471f,0.363994f,0.362517f,0.361042f, - 0.359569f,0.358097f,0.356626f,0.355156f,0.353688f,0.352221f,0.350755f,0.349291f,0.347829f,0.346368f,0.344908f, - 0.343449f,0.341993f,0.340537f,0.339083f,0.337631f,0.336180f,0.334731f,0.333283f,0.331837f,0.330393f,0.328950f, - 0.327509f,0.326069f,0.324631f,0.323194f,0.321760f,0.320327f,0.318895f,0.317466f,0.316038f,0.314611f,0.313187f, - 0.311764f,0.310343f,0.308924f,0.307507f,0.306091f,0.304678f,0.303266f,0.301856f,0.300448f,0.299041f,0.297637f, - 0.296235f,0.294834f,0.293435f,0.292039f,0.290644f,0.289251f,0.287861f,0.286472f,0.285085f,0.283700f,0.282318f, - 0.280937f,0.279558f,0.278182f,0.276808f,0.275435f,0.274065f,0.272697f,0.271331f,0.269967f,0.268606f,0.267247f, - 0.265889f,0.264534f,0.263182f,0.261831f,0.260483f,0.259137f,0.257793f,0.256451f,0.255112f,0.253775f,0.252441f, - 0.251108f,0.249779f,0.248451f,0.247126f,0.245803f,0.244483f,0.243165f,0.241849f,0.240536f,0.239225f,0.237917f, - 0.236611f,0.235308f,0.234007f,0.232709f,0.231413f,0.230120f,0.228829f,0.227541f,0.226255f,0.224972f,0.223692f, - 0.222414f,0.221139f,0.219867f,0.218597f,0.217329f,0.216065f,0.214803f,0.213544f,0.212287f,0.211033f,0.209782f, - 0.208534f,0.207288f,0.206045f,0.204805f,0.203568f,0.202333f,0.201102f,0.199873f,0.198647f,0.197423f,0.196203f, - 0.194986f,0.193771f,0.192559f,0.191350f,0.190144f,0.188941f,0.187741f,0.186544f,0.185350f,0.184158f,0.182970f, - 0.181785f,0.180603f,0.179423f,0.178247f,0.177074f,0.175904f,0.174737f,0.173572f,0.172411f,0.171254f,0.170099f, - 0.168947f,0.167799f,0.166653f,0.165511f,0.164372f,0.163236f,0.162103f,0.160973f,0.159847f,0.158723f,0.157603f, - 0.156487f,0.155373f,0.154263f,0.153156f,0.152052f,0.150951f,0.149854f,0.148760f,0.147670f,0.146582f,0.145498f, - 0.144418f,0.143340f,0.142266f,0.141196f,0.140129f,0.139065f,0.138005f,0.136948f,0.135894f,0.134844f,0.133797f, - 0.132754f,0.131714f,0.130678f,0.129645f,0.128616f,0.127590f,0.126568f,0.125549f,0.124534f,0.123522f,0.122514f, - 0.121509f,0.120508f,0.119511f,0.118517f,0.117526f,0.116540f,0.115557f,0.114577f,0.113601f,0.112629f,0.111661f, - 0.110696f,0.109734f,0.108777f,0.107823f,0.106873f,0.105926f,0.104984f,0.104045f,0.103109f,0.102178f,0.101250f, - 0.100326f,0.099406f,0.098489f,0.097576f,0.096667f,0.095762f,0.094861f,0.093963f,0.093070f,0.092180f,0.091294f, - 0.090412f,0.089533f,0.088659f,0.087788f,0.086922f,0.086059f,0.085200f,0.084345f,0.083494f,0.082647f,0.081804f, - 0.080964f,0.080129f,0.079298f,0.078470f,0.077647f,0.076828f,0.076012f,0.075201f,0.074393f,0.073590f,0.072790f, - 0.071995f,0.071204f,0.070416f,0.069633f,0.068854f,0.068078f,0.067307f,0.066540f,0.065777f,0.065019f,0.064264f, - 0.063513f,0.062767f,0.062024f,0.061286f,0.060552f,0.059822f,0.059096f,0.058374f,0.057657f,0.056943f,0.056234f, - 0.055529f,0.054828f,0.054132f,0.053439f,0.052751f,0.052067f,0.051387f,0.050711f,0.050040f,0.049373f,0.048710f, - 0.048052f,0.047397f,0.046747f,0.046101f,0.045460f,0.044822f,0.044189f,0.043561f,0.042936f,0.042316f,0.041701f, - 0.041089f,0.040482f,0.039879f,0.039281f,0.038687f,0.038097f,0.037512f,0.036930f,0.036354f,0.035781f,0.035214f, - 0.034650f,0.034091f,0.033536f,0.032986f,0.032440f,0.031898f,0.031361f,0.030828f,0.030300f,0.029776f,0.029256f, - 0.028741f,0.028231f,0.027724f,0.027223f,0.026725f,0.026233f,0.025744f,0.025260f,0.024781f,0.024306f,0.023836f, - 0.023370f,0.022908f,0.022451f,0.021999f,0.021551f,0.021107f,0.020668f,0.020234f,0.019804f,0.019379f,0.018958f, - 0.018541f,0.018130f,0.017722f,0.017320f,0.016921f,0.016528f,0.016139f,0.015754f,0.015374f,0.014999f,0.014628f, - 0.014262f,0.013900f,0.013543f,0.013191f,0.012843f,0.012499f,0.012161f,0.011827f,0.011497f,0.011172f,0.010852f, - 0.010536f,0.010225f,0.009919f,0.009617f,0.009319f,0.009027f,0.008739f,0.008455f,0.008177f,0.007903f,0.007633f, - 0.007368f,0.007108f,0.006853f,0.006602f,0.006355f,0.006114f,0.005877f,0.005645f,0.005417f,0.005194f,0.004976f, - 0.004762f,0.004553f,0.004349f,0.004149f,0.003954f,0.003764f,0.003578f,0.003397f,0.003221f,0.003049f,0.002883f, - 0.002720f,0.002563f,0.002410f,0.002262f,0.002118f,0.001980f,0.001845f,0.001716f,0.001591f,0.001471f,0.001356f, - 0.001245f,0.001140f,0.001038f,0.000942f,0.000850f,0.000763f,0.000681f,0.000603f,0.000530f,0.000462f,0.000398f, - 0.000339f,0.000285f,0.000236f,0.000191f,0.000151f,0.000115f,0.000085f,0.000059f,0.000038f,0.000021f,0.000009f, - 0.000002f,0.000000f }; - -// ----------------------------------------------------------------------------- - -OptFFT::OptFFT(const size_t maxDataSize) -{ - assert( maxDataSize % OVERLAPSAMPLES == 0 ); - - // DOUBLE - //m_pIn = static_cast( fftw_malloc(sizeof(double) * FRAMESIZE) ); - //m_pOut = static_cast( fftw_malloc(sizeof(fftw_complex) * (FRAMESIZE/2 + 1)) ); - //m_p = fftw_plan_dft_r2c_1f(FRAMESIZE, m_pIn, m_pOut, FFTW_ESTIMATE); // FFTW_ESTIMATE or FFTW_MEASURE - - // FLOAT - // m_pIn = static_cast( fftwf_malloc(sizeof(float) * FRAMESIZE) ); - // m_pOut = static_cast( fftwf_malloc(sizeof(fftwf_complex) * (FRAMESIZE/2 + 1)) ); - - //// in destroyed when line executed - //m_p = fftwf_plan_dft_r2c_1d(FRAMESIZE, m_pIn, m_pOut, FFTW_ESTIMATE); // FFTW_ESTIMATE or FFTW_MEASURE - - //----------------------------------------------------------------- - - int numSamplesPerFrame = FRAMESIZE; - int numSamplesPerFrameOut = FRAMESIZE/2+1; - - m_maxFrames = static_cast ( (maxDataSize - FRAMESIZE) / OVERLAPSAMPLES + 1 ); - - m_pIn = static_cast ( fftwf_malloc(sizeof(float) * (numSamplesPerFrame * m_maxFrames) ) ); - if ( !m_pIn ) - { - ostringstream oss; - oss << "fftwf_malloc failed on m_pIn. Trying to allocate <" - << sizeof(float) * (numSamplesPerFrame * m_maxFrames) - << "> bytes"; - throw std::runtime_error(oss.str()); - } - - m_pOut = static_cast( fftwf_malloc(sizeof(fftwf_complex) * (numSamplesPerFrameOut* m_maxFrames) ) ); - if ( !m_pOut ) - { - ostringstream oss; - oss << "fftwf_malloc failed on m_pOut. Trying to allocate <" - << sizeof(fftwf_complex) * (numSamplesPerFrameOut* m_maxFrames) - << "> bytes"; - - throw std::runtime_error(oss.str()); - } - - // in destroyed when line executed - m_p = fftwf_plan_many_dft_r2c(1, &numSamplesPerFrame, m_maxFrames, - m_pIn, &numSamplesPerFrame, 1, numSamplesPerFrame, - m_pOut, &numSamplesPerFrameOut, - 1, numSamplesPerFrameOut, - FFTW_ESTIMATE | FFTW_DESTROY_INPUT); - - if ( !m_p ) - throw std::runtime_error ("fftwf_plan_many_dft_r2c failed"); - - double base = exp( log( static_cast(MAXFREQ) / static_cast(MINFREQ) ) / - static_cast(Filter::NBANDS) - ); - - m_powTable.resize( Filter::NBANDS+1 ); - for ( unsigned int i = 0; i < Filter::NBANDS + 1; ++i ) - m_powTable[i] = static_cast( (pow(base, static_cast(i)) - 1.0) * MINCOEF ); - - m_pFrames = new float*[m_maxFrames]; - - if ( !m_pFrames ) - { - ostringstream oss; - oss << "Allocation failed on m_pFrames. Trying to allocate <" - << sizeof(float*) * m_maxFrames - << "> bytes"; - - throw std::runtime_error(oss.str()); - } - - - for (int i = 0; i < m_maxFrames; ++i) - { - m_pFrames[i] = new float[Filter::NBANDS]; - if ( !m_pFrames[i] ) - throw std::runtime_error("Allocation failed on m_pFrames"); - } - -} - -// ---------------------------------------------------------------------- - -OptFFT::~OptFFT() -{ - fftwf_destroy_plan(m_p); - - fftwf_free(m_pIn); - fftwf_free(m_pOut); - - for (int i = 0; i < m_maxFrames; ++i) - delete [] m_pFrames[i]; - - delete [] m_pFrames; -} - -// ---------------------------------------------------------------------- - -int OptFFT::process(float* pInData, const size_t dataSize) -{ - // generally is the same of the one we used in the constructor (m_maxFrames) but - // might be less at the end of the stream - int nFrames = static_cast( (dataSize - FRAMESIZE) / OVERLAPSAMPLES + 1 ); - - float* pIn_It = m_pIn; - - for (int i = 0; i < nFrames; ++i) - { - memcpy( pIn_It, &pInData[i*OVERLAPSAMPLES], sizeof(float) * FRAMESIZE); - // apply hanning window - applyHann(pIn_It, FRAMESIZE); - - pIn_It += FRAMESIZE; - } - - // fill the rest with zeroes - if ( nFrames < m_maxFrames ) - memset( pIn_It, 0, sizeof(float) * (m_maxFrames-nFrames) * FRAMESIZE ); - - fftwf_execute(m_p); - - int totSamples = (FRAMESIZE/2+1) * // numSamplesPerFrameOut - nFrames; // the frames actually in the input - - // scaling (?) - float scalingFactor = static_cast(FRAMESIZE) / 2.0f; - for (int k = 0; k < totSamples; ++k) - { - m_pOut[k][0] /= scalingFactor; - m_pOut[k][1] /= scalingFactor; - } - - int frameStart; - unsigned int outBlocStart; - unsigned int outBlocEnd; - - for (int i = 0; i < nFrames; ++i) - { - frameStart = i * (FRAMESIZE/2+1); - - // compute bands - for (unsigned int j = 0; j < Filter::NBANDS; j++) - { - outBlocStart = m_powTable[j] + frameStart; - outBlocEnd = m_powTable[j+1] + frameStart; - - m_pFrames[i][j] = 0; - - // WARNING: We're double counting the last one here. - // this bug is to match matlab's implementation bug in power2band.m - unsigned int end_k = outBlocEnd + static_cast(MINCOEF); - for (unsigned int k = outBlocStart + static_cast(MINCOEF); k <= end_k; k++) - { - m_pFrames[i][j] += m_pOut[k][0] * m_pOut[k][0] + - m_pOut[k][1] * m_pOut[k][1]; - } - - // WARNING: if we change the k<=end to k(outBlocEnd - outBlocStart + 1); - } - } - - return nFrames; -} - -// ----------------------------------------------------------------------------- - -void OptFFT::applyHann( float* pInData, const size_t dataSize ) -{ - assert (dataSize == 2048); - - for ( size_t i = 0; i < dataSize; ++i ) - pInData[i] *= hann[i]; -} - -// ----------------------------------------------------------------------------- - -} // end of namespace - -// ---------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h b/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h deleted file mode 100644 index 2a704ee73..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/OptFFT.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __OPT_FFT_H -#define __OPT_FFT_H - -#include -#include - -namespace fingerprint -{ - -class OptFFT -{ -public: - - OptFFT(const size_t maxDataSize); - ~OptFFT(); - - int - process(float* pInData, const size_t dataSize); - - float** - getFrames() { return m_pFrames; } - -private: - - void applyHann(float* pInData, const size_t dataSize); - - fftwf_plan m_p; - fftwf_complex * m_pOut; - float* m_pIn; - - //float m_base; - - int m_numSamples; - int m_numOutSamples; - - float** m_pFrames; - int m_maxFrames; - - std::vector m_powTable; - -}; - -} // end of namespace - -#endif // OPT_FFT diff --git a/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h b/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h deleted file mode 100644 index 947b63037..000000000 --- a/thirdparty/liblastfm2/src/fingerprint/fplib/fp_helper_fun.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - Copyright 2005-2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef __FINGERPRINT_HELPER_FUNCTIONS_H -#define __FINGERPRINT_HELPER_FUNCTIONS_H - -#include -#include -#include - -namespace fingerprint -{ - -// ----------------------------------------------------------------------------- - -static const size_t FINGERPRINT_LIB_VERSION = 1; -static const float QUERY_START_SECS = 20; -static const float QUERY_SIZE_SECS = 14; -static const float UPDATE_SIZE_SECS = 10; -//FFT needs also a buffer that depends on the input freq. 3 secs should be enough up to 48Khz -static const float GUARD_SIZE_SECS = 3; -static const float NORMALIZATION_SKIP_SECS = 2.5; -static const int MIN_UNIQUE_KEYS = 75; -static const unsigned int MAX_GOOD_GROUP_SIZE = 200; -static const int SHA_SIZE = 32; - -///////////////////////////////////////////////////// -// For FFT. DO NOT TOUCH THEM! -// number of samples in a frame -static const int FRAMESIZE = 2048; -static const int OVERLAP = 32; -static const int OVERLAPSAMPLES = (FRAMESIZE/OVERLAP); // 64 - -// down-sampled frequency -static const int DFREQ = 5512; -static const float FDFREQ = 5512.5f; - -// ----------------------------------------------------------------------------- - -struct GroupData -{ - unsigned int key; // the key (or local descriptor) - unsigned int count; // the number of frames sharing this key -}; - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- - -inline -unsigned int getTotalKeys( - int mSecs ) -{ - return static_cast((static_cast(mSecs) / (1000.0 * OVERLAPSAMPLES) ) * DFREQ ) + 1; -} - -// ----------------------------------------------------------------------------- - -template -void simpleSkip( - GroupDataIt& begIt, const GroupDataIt& endIt, - unsigned int numSkipKeys ) -{ - if ( numSkipKeys <= 0 ) - return; - - unsigned int nKeys; - for ( nKeys = 0; nKeys < numSkipKeys && begIt != endIt; ++begIt ) - nKeys += begIt->count; - - // clear crop at the end - if ( nKeys > numSkipKeys ) - { - --begIt; - begIt->count = nKeys - numSkipKeys; - } - -} - -// ----------------------------------------------------------------------------- - -template -void cutGroups( - std::vector& groups, - const unsigned int startMS, - const unsigned int lengthMS ) -{ - typename std::vector::iterator itBeg = groups.begin(), itEnd = groups.begin(); - - unsigned int keys_begin, keys_end; - - for (keys_begin = getTotalKeys(startMS); - itBeg != groups.end() && keys_begin > itBeg->count; ++itBeg) - keys_begin -= itBeg->count; - - for (keys_end = getTotalKeys(startMS + lengthMS); - itEnd != groups.end() && keys_end > itEnd->count; ++itEnd) - keys_end -= itEnd->count; - - if (itBeg == groups.end()) // in the umpossible scenario that you try to cut past the size of the groups - { - groups.clear(); - return; - } - - itBeg->count -= keys_begin; - if (keys_end > 0 && itEnd != groups.end()) - { - itEnd->count = keys_end; - ++itEnd; - } - - copy(itBeg, itEnd, groups.begin()); - groups.resize(itEnd - itBeg); - - keys_begin = getTotalKeys(lengthMS); - for (typename std::vector::iterator it = groups.begin(); it != groups.end(); ++it) - keys_begin -= it->count; -} - -// ------------------------------------------------------------------------- - -template -void keys2GroupData( - const std::vector& keys, // in - std::vector& groupData, - bool clearDst = true ) // out -{ - if (clearDst) - groupData.clear(); - - if (keys.empty()) - return; - - TGroupData tmpGroup; - std::vector::const_iterator it = keys.begin(); - - if ( !groupData.empty() ) - { - // get the last group - tmpGroup = groupData.back(); - groupData.pop_back(); - } - else - { - // new group! - tmpGroup.key = *it; - tmpGroup.count = 1; - ++it; // move to the next key - } - - for (; it != keys.end(); ++it) - { - if ( *it != tmpGroup.key ) - { - // new group ready! - groupData.push_back( tmpGroup ); - tmpGroup.key = *it; - tmpGroup.count = 0; - } - - ++tmpGroup.count; - } - - // last group - groupData.push_back( tmpGroup ); -} - -// ------------------------------------------------------------------------- - -template -void keys2GroupData( - const std::vector& keys, // in - std::deque& groupData, - bool clearDst = true ) // out -{ - if (clearDst) - groupData.clear(); - - if (keys.empty()) - return; - - TGroupData tmpGroup; - std::vector::const_iterator it = keys.begin(); - - if ( !groupData.empty() ) - { - // get the last group - tmpGroup = groupData.back(); - groupData.pop_back(); - } - else - { - // new group! - tmpGroup.key = *it; - tmpGroup.count = 1; - ++it; // move to the next key - } - - for (; it != keys.end(); ++it) - { - if ( *it != tmpGroup.key ) - { - // new group ready! - groupData.push_back( tmpGroup ); - tmpGroup.key = *it; - tmpGroup.count = 0; - } - - ++tmpGroup.count; - } - - // last group - groupData.push_back( tmpGroup ); -} - -// ------------------------------------------------------------------------- - -template -inline -void groupData2Keys( - const std::vector& groupData, // in - std::vector& keys ) // out -{ - keys.clear(); - - typename std::vector::const_iterator it; - - for (it = groupData.begin(); it != groupData.end(); ++it) - { - for (unsigned int j = 0; j < it->count; ++j) - keys.push_back(it->key); - } -} - -// ------------------------------------------------------------------------- - -template -bool findSignificantGroups( - GroupDataIt& beg, GroupDataIt& end, unsigned int& offset_left, unsigned int& offset_right, - unsigned int windowKeySize, unsigned int subWindowKeySize, unsigned int minUniqueKeys) -{ - GroupDataIt itBeg = beg, itEnd = beg, itWindowBeg = beg, itWindowEnd = beg; - - offset_left = 0; - unsigned int window_offset_left; - unsigned int window_offset_right; - - // this amounts to around a 500 ms hop for, say, a 20 second sub-window - unsigned int key_hop_size = subWindowKeySize / 40; - - // trail out itEnd - for (offset_right = windowKeySize; itEnd != end && offset_right > itEnd->count; ++itEnd) - offset_right -= itEnd->count; - - // dang man, we don't even have enough groups to span the window size - if (itEnd == end && offset_right > 0) - return false; - - // 0 window size means just scan the whole range - if (windowKeySize == 0) - itEnd = end; - - // trail out itWindowBeg - for (window_offset_left = (windowKeySize - subWindowKeySize) / 2; - window_offset_left > itWindowBeg->count; ++itWindowBeg) - window_offset_left -= itWindowBeg->count; - - // trail out itWindowEnd - for (window_offset_right = (windowKeySize + subWindowKeySize) / 2; - window_offset_right > itWindowEnd->count; ++itWindowEnd) - window_offset_right -= itWindowEnd->count; - - while (itEnd != end) - { - if (enoughUniqueGoodGroups(itWindowBeg, itWindowEnd, minUniqueKeys)) - { - beg = itBeg; - end = itEnd; - return true; - } - - // okay, jump key_hop_size on end iterator - for (offset_right += key_hop_size; itEnd != end && offset_right > itEnd->count; ++itEnd) - offset_right -= itEnd->count; - - // if we didn't hop the full hop size, modify the hop size to only hop as far as we hopped - if (itEnd == end) - key_hop_size -= offset_right; - - for (offset_left += key_hop_size; offset_left > itBeg->count; ++itBeg) - offset_left -= itBeg->count; - for (window_offset_right += key_hop_size; window_offset_right > itWindowEnd->count; ++itWindowEnd) - window_offset_right -= itWindowEnd->count; - for (window_offset_left += key_hop_size; window_offset_left > itWindowBeg->count; ++itWindowBeg) - window_offset_left -= itWindowBeg->count; - } - - beg = itBeg; - end = itEnd; - - return enoughUniqueGoodGroups(itWindowBeg, itWindowEnd, minUniqueKeys); -} - -// ----------------------------------------------------------------------------- - -template -bool -reduceGroups( - std::vector& groups, unsigned int startKeySize, - unsigned int windowKeySize, unsigned int subWindowKeySize, unsigned int minUniqueKeys ) -{ - unsigned int offset_left = 0; - unsigned int offset_right = 0; - - typename std::vector::iterator begIt = groups.begin(); - typename std::vector::iterator endIt = groups.end(); - - simpleSkip(begIt, endIt, startKeySize); - bool result = findSignificantGroups( begIt, endIt, - offset_left, offset_right, - windowKeySize, subWindowKeySize, minUniqueKeys ); - - if ( !result ) - { - groups.clear(); - return false; - } - - begIt->count -= offset_left; - if (offset_right > 0 && endIt != groups.end()) - { - endIt->count = offset_right; - ++endIt; - } - - std::vector resGrups(begIt, endIt); - groups.swap(resGrups); - - return true; -} - - -// ------------------------------------------------------------------------- - -template -inline bool enoughUniqueGoodGroups( - const GroupDataIt& beg, - const GroupDataIt& end, - unsigned int minUniqueKeys) -{ - std::set groupKeys; - - for (GroupDataIt it = beg; it != end && static_cast(groupKeys.size()) < minUniqueKeys; ++it) - { - if (it->count > MAX_GOOD_GROUP_SIZE) - return false; - - groupKeys.insert(it->key); - } - - return static_cast(groupKeys.size()) >= minUniqueKeys; -} - -// ----------------------------------------------------------------------------- -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -// Used by the fingerprint keys operation - -// minimum and maximum frequency to consider -#define MINFREQ 300 -#define MAXFREQ 2000 - -// amount of time in a frame -#define FRAME_TLEN ((float) FRAMESIZE / (float) DFREQ) -#define MINCOEF (FRAME_TLEN * MINFREQ) - -#define round__(x) ((int)(x + .5)) - -struct RawFilter -{ - unsigned int ftid; - float thresh; - float weight; -}; - -const RawFilter rFilters[] = { - { 26752, -4.37515e-07f, 0.260836f }, // filterID, threshold, alpha (weight) - { 23871, -2.44615e-05f, 0.263986f }, - { 26777, -3.69244e-08f, 0.267763f }, - { 4635, -1.13672e-05f, 0.269428f }, - { 2937, 5.28804e-09f, 0.271896f }, - { 27405, -0.000126494f, 0.272362f }, - { 10782, 4.27478e-08f, 0.272609f }, - { 21033, -6.7912e-07f, 0.276099f }, - { 27117, 8.07178e-06f, 0.277762f }, - { 27072, 2.46044e-05f, 0.27883f }, - { 24228, 4.11255e-07f, 0.281743f }, - { 23838, 0.000228396f, 0.284479f }, - { 17165, -1.19495e-07f, 0.286304f }, - { 25263, 0.000398279f, 0.287066f }, - { 20721, 7.15095e-07f, 0.288913f }, - { 8502, -2.78361e-07f, 0.290424f }, - { 17175, -1.08429e-08f, 0.292219f }, - { 17811, -3.29527e-08f, 0.292554f }, - { 27495, -4.47575e-07f, 0.290119f }, - { 23538, -3.04273e-09f, 0.294539f }, - { 8205, 4.02691e-07f, 0.293525f }, - { 12177, 1.16873e-06f, 0.293832f }, - { 27051, -0.000902544f, 0.296453f }, - { 27111, -2.38425e-05f, 0.297428f }, - { 21779, -1.0669e-07f, 0.297302f }, - { 14817, -9.52849e-09f, 0.299f }, - { 27087, 1.22163e-05f, 0.296502f }, - { 27081, -2.8758e-09f, 0.300112f }, - { 20394, 1.28237e-06f, 0.298693f }, - { 28209, 0.000624447f, 0.29812f }, - { 23533, -2.19406e-06f, 0.299773f }, - { 23865, -1.28037e-08f, 0.300777f } // this is iteration 1 -}; - -// ----------------------------------------------------------------------------- - -} - -// ----------------------------------------------------------------------------- - -#endif // __FINGERPRINT_HELPER_FUNCTIONS_H - diff --git a/thirdparty/liblastfm2/src/global.h b/thirdparty/liblastfm2/src/global.h deleted file mode 100644 index 8a513d802..000000000 --- a/thirdparty/liblastfm2/src/global.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef LASTFM_GLOBAL_H -#define LASTFM_GLOBAL_H - -#define LASTFM_VERSION 0x00000400 -#define LASTFM_VERSION_STRING "0.4.0" -#define LASTFM_MAJOR_VERSION 0 -#define LASTFM_MINOR_VERSION 4 -#define LASTFM_PATCH_VERSION 0 - - -#include - -#ifndef LASTFM_LIB_STATIC -#ifdef LASTFM_LIB - #define LASTFM_DLLEXPORT Q_DECL_EXPORT -#else - #define LASTFM_DLLEXPORT Q_DECL_IMPORT -#endif -#ifdef LASTFM_FINGERPRINT_LIB - #define LASTFM_FINGERPRINT_DLLEXPORT Q_DECL_EXPORT -#else - #define LASTFM_FINGERPRINT_DLLEXPORT Q_DECL_IMPORT -#endif -#else // LASTFM_LIB_STATIC - #define LASTFM_DLLEXPORT - #define LASTFM_FINGERPRINT_DLLEXPORT -#endif // LASTFM_LIB_STATIC - - -#include -#include - -namespace lastfm -{ - /** http://labs.trolltech.com/blogs/2008/10/09/coding-tip-pretty-printing-enum-values - * Tips for making this take a single parameter welcome! :) - * - * eg. lastfm::qMetaEnumString( error, "NetworkError" ); - */ - template static inline QString qMetaEnumString( int enum_value, const char* enum_name ) - { - QMetaObject meta = T::staticMetaObject; - for (int i=0; i < meta.enumeratorCount(); ++i) - { - QMetaEnum m = meta.enumerator(i); - if (m.name() == QLatin1String(enum_name)) - return QLatin1String(m.valueToKey(enum_value)); - } - return QString("Unknown enum value for \"%1\": %2").arg( enum_name ).arg( enum_value ); - } - - - enum ImageSize - { - Small, - Medium, - Large, /** seemingly 174x174 */ - ExtraLarge, - Mega - }; - - - //convenience - class Album; - class Artist; - class Audioscrobbler; - class AuthenticatedUser; - class Fingerprint; - class FingerprintableSource; - class FingerprintId; - class Mbid; - class MutableTrack; - class NetworkAccessManager; - class Playlist; - class User; - class RadioStation; - class Tag; - class Track; - class XmlQuery; - class Xspf; -} - - -#ifdef LASTFM_COLLAPSE_NAMESPACE -using lastfm::Album; -using lastfm::Artist; -using lastfm::Audioscrobbler; -using lastfm::AuthenticatedUser; -using lastfm::Fingerprint; -using lastfm::FingerprintId; -using lastfm::Mbid; -using lastfm::MutableTrack; -using lastfm::Playlist; -using lastfm::User; -using lastfm::RadioStation; -using lastfm::Tag; -using lastfm::Track; -using lastfm::XmlQuery; -using lastfm::Xspf; -#endif - - -//convenience -class QDomDocument; -class QNetworkAccessManager; -class QNetworkReply; - - -//convenience for development -#include - -#endif //LASTFM_GLOBAL_H diff --git a/thirdparty/liblastfm2/src/lastfm.pro b/thirdparty/liblastfm2/src/lastfm.pro deleted file mode 100644 index e3ae70af6..000000000 --- a/thirdparty/liblastfm2/src/lastfm.pro +++ /dev/null @@ -1,87 +0,0 @@ -TEMPLATE = lib -QT = core network xml - -INSTALLS = target -target.path = /lib - -win32{ - DEFINES += LASTFM_LIB _ATL_DLL - LIBS += winhttp.lib wbemuuid.lib # ws configuration -} -mac{ - LIBS += -framework SystemConfiguration # ws configuration - #TODO we should only use these with the carbon version of Qt! - LIBS += -framework Carbon -framework CoreFoundation # various -} - -linux*{ - QT += dbus -} - -SOURCES += \ - ws/ws.cpp \ - ws/NetworkConnectionMonitor.cpp \ - ws/NetworkAccessManager.cpp \ - ws/InternetConnectionMonitor.cpp \ - types/Xspf.cpp \ - types/User.cpp \ - types/Track.cpp \ - types/Tasteometer.cpp \ - types/Tag.cpp \ - types/Playlist.cpp \ - types/Mbid.cpp \ - types/FingerprintId.cpp \ - types/Artist.cpp \ - types/Album.cpp \ - scrobble/ScrobbleCache.cpp \ - scrobble/Audioscrobbler.cpp \ - radio/RadioTuner.cpp \ - radio/RadioStation.cpp \ - core/XmlQuery.cpp \ - core/UrlBuilder.cpp \ - core/misc.cpp - -HEADERS += \ - ws/ws.h \ - ws/NetworkConnectionMonitor.h \ - ws/NetworkAccessManager.h \ - ws/InternetConnectionMonitor.h \ - types/Xspf.h \ - types/User.h \ - types/Track.h \ - types/Tasteometer.h \ - types/Tag.h \ - types/Playlist.h \ - types/Mbid.h \ - types/FingerprintId.h \ - types/Artist.h \ - types/Album.h \ - types/AbstractType.h \ - scrobble/ScrobblePoint.h \ - scrobble/ScrobbleCache.h \ - scrobble/Audioscrobbler.h \ - radio/RadioTuner.h \ - radio/RadioStation.h \ - global.h \ - core/XmlQuery.h \ - core/UrlBuilder.h \ - core/misc.h - -win32:SOURCES += ws/win/WNetworkConnectionMonitor_win.cpp \ - ws/win/WmiSink.cpp \ - ws/win/Pac.cpp \ - ws/win/NdisEvents.cpp - -win32:HEADERS += ws/win/WNetworkConnectionMonitor.h \ - ws/win/WmiSink.h \ - ws/win/Pac.h \ - ws/win/NdisEvents.h \ - ws/win/IeSettings.h \ - ws/win/ComSetup.h - -mac:SOURCES += ws/mac/MNetworkConnectionMonitor_mac.cpp - -mac:HEADERS += ws/mac/ProxyDict.h \ - ws/mac/MNetworkConnectionMonitor.h - -!win32:VERSION = 0.4.0 diff --git a/thirdparty/liblastfm2/src/radio/RadioStation.cpp b/thirdparty/liblastfm2/src/radio/RadioStation.cpp deleted file mode 100755 index c0889d409..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioStation.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include - -#include "RadioStation.h" -#include "../core/XmlQuery.h" - - -const float k_defaultRep(0.5); -const float k_defaultMainstr(0.5); -const bool k_defaultDisco(false); - -lastfm::RadioStation -lastfm::RadioStation::library( const lastfm::User& user ) -{ - QList users; - users << user; - return library( users ); -} - -lastfm::RadioStation -lastfm::RadioStation::library( QList& users ) -{ - RadioStation s( libraryStr( users ) ); - if( users.count() == 1 ) - s.setTitle( QObject::tr( "%1%2s Library Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - - else { - QString title; - for( QList::const_iterator i = users.begin(); i != users.end(); i++ ) { - if( i == users.end() - 1 ) - title += " and " + *i; - else - title += ", " + *i; - } - - s.setTitle( title ); - } - - return s; -} - - -lastfm::RadioStation -lastfm::RadioStation::recommendations( const lastfm::User& user ) -{ - RadioStation s( recommendationsStr( user ) ); - - s.setTitle( QObject::tr( "%1%2s Recommended Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - - return s; -} - -lastfm::RadioStation -lastfm::RadioStation::friends( const lastfm::User& user ) -{ - RadioStation s( friendsStr( user ) ); - - s.setTitle( QObject::tr( "%1%2s Friends Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - - return s; -} - -lastfm::RadioStation -lastfm::RadioStation::neighbourhood( const lastfm::User& user ) -{ - RadioStation s( neighbourhoodStr( user ) ); - s.setTitle( QObject::tr( "%1%2s Neighbours%2 Radio").arg( lastfm::ws::Username, QChar(0x2019) )); - return s; -} - - -lastfm::RadioStation -lastfm::RadioStation::tag( const lastfm::Tag& tag ) -{ - QList tags; - tags << tag; - return lastfm::RadioStation::tag( tags ); -} - - -lastfm::RadioStation -lastfm::RadioStation::tag( QList& tag ) -{ - return RadioStation( tagStr( tag ) ); -} - - -lastfm::RadioStation -lastfm::RadioStation::similar( const lastfm::Artist& artist ) -{ - QList artists; - artists << artist; - return similar( artists ); -} - - -lastfm::RadioStation -lastfm::RadioStation::similar( QList& artists ) -{ - return RadioStation( similarStr( artists ) ); -} - - -lastfm::RadioStation -lastfm::RadioStation::mix( const lastfm::User& user ) -{ - RadioStation s( mixStr( user ) ); - s.setTitle( QObject::tr( "%1%2s Mix Radio").arg( lastfm::ws::Username, QChar(0x2019) ) ); - return s; -} - - -QString -lastfm::RadioStation::url() const -{ - return m_url.toString() + (m_tagFilter.isEmpty() ? "" : "/tag/" + m_tagFilter); -} - - -void -lastfm::RadioStation::setTitle( const QString& s ) -{ - // Stop the radio station getting renamed when the web services don't know what it's called - if ( !m_title.isEmpty() && s.compare( "a radio station", Qt::CaseInsensitive ) == 0 ) - return; - - QString title = s.trimmed(); - - if ( title.compare( QObject::tr("%1%2s Library Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Library Radio"); - else if ( title.compare( QObject::tr("%1%2s Mix Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Mix Radio"); - else if ( title.compare( QObject::tr("%1%2s Recommended Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Recommended Radio"); - else if ( title.compare( QObject::tr("%1%2s Friends%2 Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Friends%1 Radio").arg( QChar( 0x2019 ) ); - else if ( title.compare( QObject::tr("%1%2s Friends Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Friends%1 Radio").arg( QChar( 0x2019 ) ); - else if ( title.compare( QObject::tr("%1%2s Neighbours%2 Radio").arg( lastfm::ws::Username, QChar(0x2019) ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Neighbours%1 Radio").arg( QChar( 0x2019 ) ); - else if ( title.compare( QObject::tr("%1%2s Neighbours Radio").arg( lastfm::ws::Username ), Qt::CaseInsensitive ) == 0 ) - title = QObject::tr("My Neighbours%1 Radio").arg( QChar( 0x2019 ) ); - - m_title = title; -} - - -QString -lastfm::RadioStation::title() const -{ - return m_title; // + (m_tagFilter.isEmpty() ? "" : ": " + m_tagFilter); -} - - -void -lastfm::RadioStation::setTagFilter( const QString& tag ) -{ - m_tagFilter = tag; -} - - -QNetworkReply* -lastfm::RadioStation::getSampleArtists( int limit ) const -{ - QMap map; - map["method"] = "radio.getSampleArtists"; - map["station"] = m_url.toString(); - map["limit"] = QString::number( limit ); - return ws::get( map ); -} - - -QNetworkReply* -lastfm::RadioStation::getTagSuggestions( int limit ) const -{ - QMap map; - map["method"] = "radio.getTagSuggestions"; - map["station"] = m_url.toString(); - map["limit"] = QString::number( limit ); - return ws::get( map ); -} - - -//static -QList -lastfm::RadioStation::list( QNetworkReply* r ) -{ - QList result; - try { - foreach (XmlQuery xq, XmlQuery( r->readAll() ).children("station")) { - lastfm::RadioStation rs( QUrl::fromPercentEncoding( xq["url"].text().toUtf8() ) ); - rs.setTitle(xq["name"].text()); - result.append(rs); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return result; -} - - -bool -lastfm::RadioStation::operator==( const RadioStation& that ) const -{ - return this->m_url == that.m_url && this->m_tagFilter == that.m_tagFilter; -} - - -void -lastfm::RadioStation::setString( const QString& string ) -{ - // If it's a tag filtered station then extract that part - QString tempString = string; - - if ( !tempString.startsWith("lastfm://tag/") ) - { - int index = tempString.indexOf("/tag/"); - - if ( index != -1 ) - { - m_tagFilter = tempString.mid( index + 5, tempString.count() - (index + 5) ); - tempString = tempString.mid( 0, index ); - } - } - - m_url = tempString; -} - - -void -lastfm::RadioStation::setRep(float rep) -{ - m_rep = rep; -} - - -void -lastfm::RadioStation::setMainstr(float mainstr) -{ - m_mainstr = mainstr; -} - - -void -lastfm::RadioStation::setDisco(bool disco) -{ - m_disco = disco; -} - - -float lastfm::RadioStation::rep() const -{ - return m_rep; -} - - -float lastfm::RadioStation::mainstr() const -{ - return m_mainstr; -} - - -bool lastfm::RadioStation::disco() const -{ - return m_disco; -} - - -QString lastfm::RadioStation::libraryStr( QList& users ) -{ - qSort(users.begin(), users.end()); - - QString url = (users.count() > 1) ? "lastfm://users/" : "lastfm://user/"; - - url.append( users[0].name() ); - - for ( int i = 1 ; i < users.count() ; ++i ) - url.append( "," + users[i].name() ); - - url.append("/personal"); - - return url; -} - - -QString lastfm::RadioStation::tagStr( QList& tags ) -{ - qSort(tags.begin(), tags.end()); - - QString url = (tags.count() > 1) ? "lastfm://tag/" : "lastfm://globaltags/"; - - url.append( tags[0].name() ); - - for ( int i = 1 ; i < tags.count() ; ++i ) - url.append( "*" + tags[i].name() ); - - return url; -} - - -QString lastfm::RadioStation::similarStr( QList& artists ) -{ - qSort(artists.begin(), artists.end()); - - QString url = (artists.count() > 1) ? "lastfm://artistnames/" : "lastfm://artist/"; - - url.append( artists[0].name() ); - - for ( int i = 1 ; i < artists.count() ; ++i ) - url.append( "," + artists[i].name() ); - - if (artists.count() == 1) - url.append( "/similarartists" ); - - return url; -} diff --git a/thirdparty/liblastfm2/src/radio/RadioStation.h b/thirdparty/liblastfm2/src/radio/RadioStation.h deleted file mode 100644 index 816c49657..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioStation.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_RADIO_STATION_H -#define LASTFM_RADIO_STATION_H - -#include -#include -#include - -namespace lastfm -{ - /** @author - */ - class LASTFM_DLLEXPORT RadioStation - { - public: - RadioStation() - {} - RadioStation( const QString& s ) - { - setString( s ); - } - - static RadioStation library( const lastfm::User& user ); - static RadioStation library( QList& users ); - - static RadioStation similar( const lastfm::Artist& artist ); - static RadioStation similar( QList& artist ); - - static RadioStation tag( const lastfm::Tag& tag ); - static RadioStation tag( QList& tag ); - - static RadioStation recommendations( const lastfm::User& user ); - static RadioStation friends( const lastfm::User& user ); - static RadioStation neighbourhood( const lastfm::User& user ); - - static RadioStation mix( const lastfm::User& user ); - - QNetworkReply* getSampleArtists( int limit = 50 ) const; - QNetworkReply* getTagSuggestions( int limit = 50 ) const; - - /** eg. "mxcl's Loved Tracks" - * It is worth noting that the Radio doesn't set the title of RadioStation - * object until we have tuned to it, and then we only set the one we give - * you back. - */ - QString title() const; - /** the Last.fm url, eg. lastfm://user/mxcl/loved */ - QString url() const; - - void setTitle( const QString& title ); - - void setTagFilter( const QString& tag ); - - void setRep(float rep); - void setMainstr(float mainstr); - void setDisco(bool disco); - - float rep() const; - float mainstr() const; - bool disco() const; - - bool isLegacyPlaylist() const - { - return m_url.toString().startsWith( "lastfm://play/" ) || - m_url.toString().startsWith( "lastfm://preview/" ) || - m_url.toString().startsWith( "lastfm://track/" ) || - m_url.toString().startsWith( "lastfm://playlist/" ); - } - - // good for getRecentStations: - static QList list( QNetworkReply* ); - - bool operator==( const RadioStation& that ) const; - - private: - void setString( const QString& s ); - - static QString libraryStr( QList& user ); - static QString recommendationsStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/recommended"; } - static QString friendsStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/friends"; } - static QString neighbourhoodStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/neighbours"; } - static QString tagStr( QList& tag ); - static QString similarStr( QList& artist ); - static QString mixStr( const lastfm::User& user ) { return "lastfm://user/" + user + "/mix"; } - private: - QUrl m_url; - QString m_title; - QString m_tagFilter; - - float m_rep; - float m_mainstr; - bool m_disco; - }; -} - - -Q_DECLARE_METATYPE( lastfm::RadioStation ) - - -inline QDebug operator<<( QDebug d, const lastfm::RadioStation& station ) -{ - return d << station.url(); -} - -#endif diff --git a/thirdparty/liblastfm2/src/radio/RadioTuner.cpp b/thirdparty/liblastfm2/src/radio/RadioTuner.cpp deleted file mode 100644 index 9f875ee22..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioTuner.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include - -#include "RadioTuner.h" -#include "../core/XmlQuery.h" -#include "../types/Xspf.h" -#include "../ws/ws.h" - -using namespace lastfm; - -//TODO skips left -//TODO multiple locations for the same track -//TODO set rtp flag in getPlaylist (whether user is scrobbling this radio session or not) - -// limit the number of retries following empty playlists: -#define MAX_TUNING_ATTEMPTS 3 - - -RadioTuner::RadioTuner( const RadioStation& station ) - : m_retry_counter( 0 ), m_fetchingPlaylist( false ), m_requestedPlaylist(false) -{ - m_twoSecondTimer = new QTimer( this ); - m_twoSecondTimer->setSingleShot( true ); - connect( m_twoSecondTimer, SIGNAL(timeout()), SLOT(onTwoSecondTimeout())); - - qDebug() << station.url(); - - //Empty RadioStation implies that the radio - //should tune to the previous station. - if( station.url().isEmpty() ) - { - fetchFiveMoreTracks(); - } - else - { - QMap map; - map["method"] = "radio.tune"; - map["station"] = station.url(); - map["additional_info"] = "1"; - connect( ws::post(map), SIGNAL(finished()), SLOT(onTuneReturn()) ); - } -} - -void -RadioTuner::retune( const RadioStation& station ) -{ - m_playlistQueue.clear(); - m_retuneStation = station; - - qDebug() << station.url(); -} - - -void -RadioTuner::onTuneReturn() -{ - try { - XmlQuery lfm = qobject_cast(sender())->readAll(); - emit title( lfm["station"]["name"].text() ); - - qDebug() << lfm; - - emit supportsDisco( lfm["station"]["supportsdiscovery"].text() == "1" ); - fetchFiveMoreTracks(); - } - catch (ws::ParseError& e) - { - emit error( e.enumValue(), e.message() ); - } -} - - -void -RadioTuner::fetchFiveMoreTracks() -{ - if ( !m_retuneStation.url().isEmpty() ) - { - // We have been asked to retune so do it now - QMap map; - map["method"] = "radio.tune"; - map["station"] = m_retuneStation.url(); - map["additional_info"] = "1"; - - QNetworkReply* reply = ws::post(map); - connect( reply, SIGNAL(finished()), SLOT(onTuneReturn()) ); - - m_retuneStation = RadioStation(); - m_twoSecondTimer->stop(); - } - else - { - if ( !m_twoSecondTimer->isActive() ) - { - //TODO check documentation, I figure this needs a session key - QMap map; - map["method"] = "radio.getPlaylist"; - map["additional_info"] = "1"; - map["rtp"] = "1"; // see above - connect( ws::post( map ), SIGNAL(finished()), SLOT(onGetPlaylistReturn()) ); - m_fetchingPlaylist = true; - } - else - m_requestedPlaylist = true; - } -} - - -bool -RadioTuner::tryAgain() -{ - qDebug() << "Bad response count" << m_retry_counter; - - if (++m_retry_counter > MAX_TUNING_ATTEMPTS) - return false; - fetchFiveMoreTracks(); - return true; -} - - -void -RadioTuner::onGetPlaylistReturn() -{ - // We shouldn't request another playlist for 2 seconds because we'll get the same one - // in a different order. This QTimer will block until it has finished. If one or more - // playlists have been requested in the meantime, it will fetch one on timeout - m_twoSecondTimer->start( 2000 ); - - // This will block us fetching two playlists at once - m_fetchingPlaylist = false; - - try { - XmlQuery lfm = qobject_cast(sender())->readAll(); - emit title( lfm["playlist"]["title"].text() ); - - qDebug() << lfm; - - Xspf* xspf = new Xspf( lfm["playlist"], this ); - connect( xspf, SIGNAL(expired()), SLOT(onXspfExpired()) ); - - if ( xspf->isEmpty() ) - { - // give up after too many empty playlists :( - if (!tryAgain()) - emit error( ws::NotEnoughContent, tr("Not enough content") ); - } - else - { - m_retry_counter = 0; - m_playlistQueue << xspf; - emit trackAvailable(); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - emit error( e.enumValue(), e.message() ); - } -} - -void -RadioTuner::onTwoSecondTimeout() -{ - if (m_requestedPlaylist) - { - m_requestedPlaylist = false; - fetchFiveMoreTracks(); - } -} - -void -RadioTuner::onXspfExpired() -{ - int index = m_playlistQueue.indexOf( static_cast(sender()) ); - if ( index != -1 ) - m_playlistQueue.takeAt( index )->deleteLater(); -} - -Track -RadioTuner::takeNextTrack() -{ - if ( m_playlistQueue.isEmpty() ) - { - // If there are no tracks here and we're not fetching tracks - // it's probably because the playlist expired so fetch more now - if ( !m_fetchingPlaylist ) - fetchFiveMoreTracks(); - - return Track(); - } - - Track result = m_playlistQueue[0]->takeFirst(); - - if ( m_playlistQueue[0]->isEmpty() ) - m_playlistQueue.removeFirst(); - - if ( m_playlistQueue.isEmpty() ) - fetchFiveMoreTracks(); - - return result; -} diff --git a/thirdparty/liblastfm2/src/radio/RadioTuner.h b/thirdparty/liblastfm2/src/radio/RadioTuner.h deleted file mode 100644 index 7193d53ab..000000000 --- a/thirdparty/liblastfm2/src/radio/RadioTuner.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_TUNER_H -#define LASTFM_TUNER_H - -#include -#include -#include -#include -#include - -namespace lastfm -{ - /** With regard to error handling. We handle Ws::TryAgain up to 5 times, - * don't try again after that! Just tell the user to try again later. - */ - class LASTFM_DLLEXPORT RadioTuner : public QObject - { - Q_OBJECT - - public: - /** You need to have assigned Ws::* for this to work, creating the tuner - * automatically fetches the first 5 tracks for the station */ - explicit RadioTuner( const RadioStation& ); - - Track takeNextTrack(); - - void retune( const RadioStation& ); - - signals: - void title( const QString& ); - void supportsDisco( bool supportsDisco ); - void trackAvailable(); - void error( lastfm::ws::Error, const QString& message ); - - private slots: - void onTuneReturn(); - void onGetPlaylistReturn(); - void onXspfExpired(); - - void onTwoSecondTimeout(); - - private: - /** Tries again up to 5 times - * @returns true if we tried again, otherwise you should emit error */ - bool tryAgain(); - /** Will emit 5 tracks from tracks(), they have to played within an hour - * or the streamer will refuse to stream them. Also the previous five are - * invalidated apart from the one that is currently playing, so sorry, you - * can't build up big lists of tracks. - * - * I feel I must point out that asking the user which one they want to play - * is also not allowed according to our terms and conditions, which you - * already agreed to in order to get your API key. Sorry about that dude. - */ - void fetchFiveMoreTracks(); - - private: - QList m_playlistQueue; - uint m_retry_counter; - bool m_fetchingPlaylist; - bool m_requestedPlaylist; - class QTimer* m_twoSecondTimer; - RadioStation m_retuneStation; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp b/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp deleted file mode 100644 index a6680fbe2..000000000 --- a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include - -#include "Audioscrobbler.h" -#include "ScrobbleCache.h" - -#include "../types/User.h" -#include "../types/Track.h" -#include "../ws/ws.h" -#include "../core/XmlQuery.h" - - -namespace lastfm -{ - class AudioscrobblerPrivate - { - public: - AudioscrobblerPrivate(const QString& id) - : m_id( id ) - , m_cache( ws::Username ) - {} - - ~AudioscrobblerPrivate() - { - } - - const QString m_id; - ScrobbleCache m_cache; - QList m_batch; - QPointer m_nowPlayingReply; - QPointer m_scrobbleReply; - Track m_nowPlayingTrack; - }; -} - - -lastfm::Audioscrobbler::Audioscrobbler( const QString& id ) - : d( new AudioscrobblerPrivate(id) ) -{ - submit(); -} - - -lastfm::Audioscrobbler::~Audioscrobbler() -{ - delete d; -} - - -void -lastfm::Audioscrobbler::nowPlaying( const Track& track ) -{ - if ( d->m_nowPlayingReply.isNull()) - { - d->m_nowPlayingTrack = track; - d->m_nowPlayingReply = track.updateNowPlaying(); - connect( d->m_nowPlayingReply, SIGNAL(finished()), SLOT(onNowPlayingReturn())); - } -} - - -void -lastfm::Audioscrobbler::cache( const Track& track ) -{ - QList tracks; - tracks.append( track ); - cacheBatch( tracks ); -} - - -void -lastfm::Audioscrobbler::cacheBatch( const QList& tracks ) -{ - d->m_cache.add( tracks ); - - foreach ( const Track& track, d->m_cache.tracks() ) - MutableTrack( track ).setScrobbleStatus( Track::Cached ); - - emit scrobblesCached( tracks ); - submit(); -} - - -void -lastfm::Audioscrobbler::submit() -{ - if (d->m_cache.tracks().isEmpty() // there are no tracks to submit - || !d->m_scrobbleReply.isNull() ) // we are already submitting scrobbles - return; - - // copy tracks to be submitted to a temporary list - d->m_batch = d->m_cache.tracks().mid( 0, 50 ); - - // if there is only one track use track.scrobble, otherwise use track.scrobbleBatch - if (d->m_batch.count() == 1) - d->m_scrobbleReply = d->m_batch[0].scrobble(); - else - d->m_scrobbleReply = lastfm::Track::scrobble( d->m_batch ); - - connect( d->m_scrobbleReply, SIGNAL(finished()), SLOT(onTrackScrobbleReturn())); -} - -void -lastfm::Audioscrobbler::parseTrack( const XmlQuery& trackXml, const Track& track ) -{ - MutableTrack mTrack = MutableTrack( track ); - bool isScrobble = QDomElement(trackXml).tagName() == "scrobble"; - - if ( trackXml["ignoredMessage"].attribute("code") == "0" ) - { - if ( isScrobble ) mTrack.setScrobbleStatus( Track::Submitted ); - - // corrections! - if ( trackXml["track"].attribute("corrected") == "1" - || trackXml["artist"].attribute("corrected") == "1" - || trackXml["album"].attribute("corrected") == "1" - || trackXml["albumArtist"].attribute("corrected") == "1") - { - mTrack.setCorrections(trackXml["track"].text(), - trackXml["album"].text(), - trackXml["artist"].text(), - trackXml["albumArtist"].text()); - } - } - else if ( isScrobble ) - { - mTrack.setScrobbleError( static_cast(trackXml["ignoredMessage"].attribute("code").toInt()) ); - mTrack.setScrobbleStatus( Track::Error ); - } -} - -void -lastfm::Audioscrobbler::onNowPlayingReturn() -{ - try - { - lastfm::XmlQuery lfm = static_cast(sender())->readAll(); - - qDebug() << lfm; - - if ( lfm.attribute("status") == "ok" ) - parseTrack( lfm["nowplaying"], d->m_nowPlayingTrack ); - else - emit nowPlayingError( lfm["error"].attribute("code").toInt(), lfm["error"].text() ); - - d->m_nowPlayingTrack = Track(); - d->m_nowPlayingReply = 0; - } - catch ( lastfm::ws::ParseError p ) - { - qDebug() << p.message() << p.enumValue(); - } - catch ( lastfm::ws::Error p ) - { - qDebug() << p; - } - - d->m_nowPlayingTrack = Track(); - d->m_nowPlayingReply = 0; -} - - -void -lastfm::Audioscrobbler::onTrackScrobbleReturn() -{ - try - { - lastfm::XmlQuery lfm = d->m_scrobbleReply->readAll(); - - qDebug() << lfm; - - if (lfm.attribute("status") == "ok") - { - int index = 0; - - foreach ( const XmlQuery& scrobble, lfm["scrobbles"].children("scrobble") ) - parseTrack( scrobble, d->m_batch.at( index++ ) ); - - emit scrobblesSubmitted( d->m_batch ); - - d->m_cache.remove( d->m_batch ); - d->m_batch.clear(); - } - else if ( d->m_scrobbleReply->error() == QNetworkReply::NoError ) - { - // The scrobble submission failed, but the http request was sucessful - - if ( !(lfm["error"].attribute("code") == "9" // Bad session - || lfm["error"].attribute("code") == "11" // Service offline - || lfm["error"].attribute("code") == "16") ) // Service temporarily unavailable - { - foreach ( const Track& track, d->m_batch ) - { - MutableTrack mTrack = MutableTrack( track ); - mTrack.setScrobbleError( static_cast(lfm["error"].attribute("code").toInt()) ); - mTrack.setScrobbleErrorText( lfm["error"].text() ); - mTrack.setScrobbleStatus( Track::Error ); - } - - emit scrobblesSubmitted( d->m_batch ); - - // clear the cache if it was not one of these error codes - d->m_cache.remove( d->m_batch ); - d->m_batch.clear(); - } - else - { - Q_ASSERT(false); - } - } - - d->m_scrobbleReply = 0; - - // check is there are anymore scrobbles to submit - submit(); - } - catch ( lastfm::ws::ParseError p ) - { - qDebug() << p.message() << p.enumValue(); - d->m_scrobbleReply = 0; - } - catch ( lastfm::ws::Error p ) - { - qDebug() << p; - d->m_scrobbleReply = 0; - } -} diff --git a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h b/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h deleted file mode 100644 index 02e381415..000000000 --- a/thirdparty/liblastfm2/src/scrobble/Audioscrobbler.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_AUDIOSCROBBLER_H -#define LASTFM_AUDIOSCROBBLER_H - -#include -#include -#include -#include -#include -#include - -namespace lastfm -{ - /** @author Max Howell - * An implementation of the Audioscrobbler Realtime Submissions Protocol - * version 1.2.1 for a single Last.fm user - * http://www.audioscrobbler.net/development/protocol/ - */ - class LASTFM_DLLEXPORT Audioscrobbler : public QObject - { - Q_OBJECT - - public: - /** You will need to do QCoreApplication::setVersion and - * QCoreApplication::setApplicationName for this to work, also you will - * need to have set all the keys in the Ws namespace in WsKeys.h */ - Audioscrobbler( const QString& clientId ); - ~Audioscrobbler(); - - signals: - void scrobblesCached( const QList& tracks ); - /* Note that this is emitted after we tried to submit the scrobbles - It could just be that they have an error code */ - void scrobblesSubmitted( const QList& tracks ); - void nowPlayingError( int code, QString message ); - - public slots: - /** will ask Last.fm to update the now playing information for the - * authenticated user */ - void nowPlaying( const Track& ); - /** will cache the track and call submit() */ - void cache( const Track& ); - void cacheBatch( const QList& ); - - /** will submit the submission cache for this user */ - void submit(); - - private slots: - void onNowPlayingReturn(); - void onTrackScrobbleReturn(); - - private: - void parseTrack( const XmlQuery& trackXml, const Track& track ); - - private: - class AudioscrobblerPrivate* d; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp b/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp deleted file mode 100644 index 583d4b4d0..000000000 --- a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "ScrobbleCache.h" -#include "ScrobblePoint.h" -#include -#include -#include -#include -#include - -#if LASTFM_VERSION >= 0x00010000 -using lastfm::ScrobbleCache; -#endif - -ScrobbleCache::ScrobbleCache( const QString& username ) -{ - Q_ASSERT( username.length() ); - - m_path = lastfm::dir::runtimeData().filePath( username + "_subs_cache.xml" ); - m_username = username; - - QDomDocument xml; - read( xml ); -} - - -bool -ScrobbleCache::isValid( const Track& track, Invalidity* v ) -{ - #define TEST( test, x ) \ - if (test) { \ - if (v) *v = x; \ - return false; \ - } - - TEST( track.duration() < ScrobblePoint::kScrobbleMinLength, TooShort ); - - TEST( !track.timestamp().isValid(), NoTimestamp ); - - // actual spam prevention is something like 12 hours, but we are only - // trying to weed out obviously bad data, server side criteria for - // "the future" may change, so we should let the server decide, not us - TEST( track.timestamp() > QDateTime::currentDateTime().addMonths( 1 ), FromTheFuture ); - - TEST( track.timestamp() < QDateTime::fromString( "2003-01-01", Qt::ISODate ), FromTheDistantPast ); - - // Check if any required fields are empty - TEST( track.artist().isNull(), ArtistNameMissing ); - TEST( track.title().isEmpty(), TrackNameMissing ); - - TEST( (QStringList() << "unknown artist" - << "unknown" - << "[unknown]" - << "[unknown artist]").contains( track.artist().name().toLower() ), - ArtistInvalid ); - - return true; -} - - -void -ScrobbleCache::read( QDomDocument& xml ) -{ - m_tracks.clear(); - - QFile file( m_path ); - file.open( QFile::Text | QFile::ReadOnly ); - QTextStream stream( &file ); - stream.setCodec( "UTF-8" ); - - xml.setContent( stream.readAll() ); - - for (QDomNode n = xml.documentElement().firstChild(); !n.isNull(); n = n.nextSibling()) - if (n.nodeName() == "track") - m_tracks += Track( n.toElement() ); -} - - -void -ScrobbleCache::write() -{ - if (m_tracks.isEmpty()) - { - QFile::remove( m_path ); - } - else { - QDomDocument xml; - QDomElement e = xml.createElement( "submissions" ); - e.setAttribute( "product", QCoreApplication::applicationName() ); - e.setAttribute( "version", "2" ); - - foreach (Track i, m_tracks) - e.appendChild( i.toDomElement( xml ) ); - - xml.appendChild( e ); - - QFile file( m_path ); - file.open( QIODevice::WriteOnly | QIODevice::Text ); - - QTextStream stream( &file ); - stream.setCodec( "UTF-8" ); - stream << "\n"; - stream << xml.toString( 2 ); - file.close(); - } -} - - -void -ScrobbleCache::add( const QList& tracks ) -{ - foreach (const Track& track, tracks) - { - ScrobbleCache::Invalidity invalidity; - - if ( !isValid( track, &invalidity ) ) - { - qWarning() << invalidity; - } - else if (track.isNull()) - qDebug() << "Will not cache an empty track"; - else - m_tracks += track; - } - - write(); -} - - -int -ScrobbleCache::remove( const QList& toremove ) -{ - QMutableListIterator i( m_tracks ); - while (i.hasNext()) { - Track t = i.next(); - for (int x = 0; x < toremove.count(); ++x) - if (toremove[x] == t) - i.remove(); - } - - write(); - - // yes we return # remaining, rather # removed, but this is an internal - // function and the behaviour is documented so it's alright imo --mxcl - return m_tracks.count(); -} diff --git a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h b/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h deleted file mode 100644 index 31219263b..000000000 --- a/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_SCROBBLE_CACHE_H -#define LASTFM_SCROBBLE_CACHE_H - -#include "lastfm/Track" -#include -#include - -#if LASTFM_VERSION >= 0x00010000 -namespace lastfm { -#else -using lastfm::Track; -#endif - -/** absolutely not thread-safe */ -class LASTFM_DLLEXPORT ScrobbleCache -{ - QString m_username; - - void write(); /// writes m_tracks to m_path - -protected: - ScrobbleCache() - {} - - QString m_path; - QList m_tracks; - - void read( QDomDocument& xml ); /// reads from m_path into m_tracks - -public: - explicit ScrobbleCache( const QString& username ); - - /** note this is unique for Track::sameAs() and equal timestamps - * obviously playcounts will not be increased for the same timestamp */ - void add( const QList& ); - - /** returns the number of tracks left in the queue */ - int remove( const QList& ); - - QList tracks() const { return m_tracks; } - QString path() const { return m_path; } - QString username() const { return m_username; } - -private: - bool operator==( const ScrobbleCache& ); //undefined - - enum Invalidity - { - TooShort, - ArtistNameMissing, - TrackNameMissing, - ArtistInvalid, - NoTimestamp, - FromTheFuture, - FromTheDistantPast - }; - - bool isValid( const Track& track, Invalidity* = 0 ); -}; - -#if LASTFM_VERSION >= 0x00010000 -} -#endif - -#endif diff --git a/thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h b/thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h deleted file mode 100644 index fce857d46..000000000 --- a/thirdparty/liblastfm2/src/scrobble/ScrobblePoint.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_SCROBBLE_POINT_H -#define LASTFM_SCROBBLE_POINT_H - -#include -#include - - -class LASTFM_DLLEXPORT ScrobblePoint -{ - uint i; - -public: - ScrobblePoint() : i( kScrobbleTimeMax ) - {} - - /** j is in seconds, and should be 50% the duration of a track */ - explicit ScrobblePoint( uint j ) - { - // we special case 0, returning kScrobbleTimeMax because we are - // cruel and callous people - if (j == 0) --j; - - i = qBound( uint(kScrobbleMinLength), - j, - uint(kScrobbleTimeMax) ); - } - operator uint() const { return i; } - - // scrobbles can occur between these two percentages of track duration - static const uint kScrobblePointMin = 50; - static const uint kScrobblePointMax = 100; - static const uint kDefaultScrobblePoint = 50; - - // Shortest track length allowed to scrobble in seconds - static const uint kScrobbleMinLength = 31; - // Upper limit for scrobble time in seconds - static const uint kScrobbleTimeMax = 240; -}; - -#endif diff --git a/thirdparty/liblastfm2/src/types/AbstractType.h b/thirdparty/liblastfm2/src/types/AbstractType.h deleted file mode 100755 index 873b5dec9..000000000 --- a/thirdparty/liblastfm2/src/types/AbstractType.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Micahel Coffey and Jono Cole - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef ABSTRACTTYPE_H -#define ABSTRACTTYPE_H - -#include -#include -#include - -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT AbstractType - { - public: - virtual QString toString() const = 0; - virtual QDomElement toDomElement( QDomDocument& ) const = 0; - virtual QUrl www() const = 0; - virtual QUrl imageUrl( ImageSize size, bool square ) const = 0; - virtual ~AbstractType() {;} - }; -}; - -#endif // ABSTRACTTYPE_H diff --git a/thirdparty/liblastfm2/src/types/Album.cpp b/thirdparty/liblastfm2/src/types/Album.cpp deleted file mode 100644 index 8a545897d..000000000 --- a/thirdparty/liblastfm2/src/types/Album.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Album.h" -#include "Artist.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -#include -#include -#include - -QNetworkReply* -lastfm::Album::getInfo() const -{ - QMap map; - map["method"] = "album.getInfo"; - map["artist"] = m_artist; - map["album"] = m_title; - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - return lastfm::ws::get(map); -} - - -QNetworkReply* -lastfm::Album::getTags() const -{ - QMap map; - map["method"] = "album.getTags"; - map["artist"] = m_artist; - map["album"] = m_title; - return lastfm::ws::get(map); -} - - -QNetworkReply* -lastfm::Album::share( const QStringList& recipients, const QString& message, bool isPublic ) const -{ - QMap map; - map["method"] = "album.share"; - map["artist"] = m_artist; - map["album"] = m_title; - map["recipient"] = recipients.join(","); - map["public"] = isPublic ? "1" : "0"; - if (message.size()) map["message"] = message; - return lastfm::ws::post(map); -} - - -QUrl -lastfm::Album::www() const -{ - return lastfm::UrlBuilder( "music" ).slash( m_artist ).slash( m_title ).url(); -} - - -QNetworkReply* -lastfm::Album::addTags( const QStringList& tags ) const -{ - if (tags.isEmpty()) - return 0; - - QMap map; - map["method"] = "album.addTags"; - map["artist"] = m_artist; - map["album"] = m_title; - map["tags"] = tags.join( QChar(',') ); - return lastfm::ws::post(map); -} diff --git a/thirdparty/liblastfm2/src/types/Album.h b/thirdparty/liblastfm2/src/types/Album.h deleted file mode 100644 index f64b59986..000000000 --- a/thirdparty/liblastfm2/src/types/Album.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_ALBUM_H -#define LASTFM_ALBUM_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Album - { - Mbid m_mbid; - Artist m_artist; - QString m_title; - - public: - Album() - {} - - explicit Album( Mbid mbid ) : m_mbid( mbid ) - {} - - Album( Artist artist, QString title ) : m_artist( artist ), m_title( title ) - {} - - bool operator==( const Album& that ) const { return m_title == that.m_title && m_artist == that.m_artist; } - bool operator!=( const Album& that ) const { return m_title != that.m_title || m_artist != that.m_artist; } - - operator QString() const { return title(); } - QString title() const { return m_title.isEmpty() ? "[unknown]" : m_title; } - Artist artist() const { return m_artist; } - Mbid mbid() const { return m_mbid; } - - /** artist may have been set, since we allow that in the ctor, but should we handle untitled albums? */ - bool isNull() const { return m_title.isEmpty() && m_mbid.isNull(); } - - /** Album.getInfo WebService */ - QNetworkReply* getInfo() const; - QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; - - /** use Tag::list to get the tag list out of the finished reply */ - QNetworkReply* getTags() const; - QNetworkReply* getTopTags() const; - - /** Last.fm dictates that you may submit at most 10 of these */ - QNetworkReply* addTags( const QStringList& ) const; - - /** the Last.fm website url for this album */ - QUrl www() const; - }; -} - -#endif //LASTFM_ALBUM_H diff --git a/thirdparty/liblastfm2/src/types/Artist.cpp b/thirdparty/liblastfm2/src/types/Artist.cpp deleted file mode 100644 index 1d9e14258..000000000 --- a/thirdparty/liblastfm2/src/types/Artist.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Artist.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -#include -#include - -using lastfm::Artist; -using lastfm::User; -using lastfm::ImageSize; -using lastfm::XmlQuery; - -QUrl -Artist::imageUrl( ImageSize size, bool square ) const -{ - if( !square ) return m_images.value( size ); - - QUrl url = m_images.value( size ); - QRegExp re( "/serve/(\\d*)s?/" ); - return QUrl( url.toString().replace( re, "/serve/\\1s/" )); -} - -static inline QList images( const lastfm::XmlQuery& e ) -{ - QList images; - images += e["image size=small"].text(); - images += e["image size=medium"].text(); - images += e["image size=large"].text(); - return images; -} - - -Artist::Artist( const XmlQuery& xml ) - :AbstractType() -{ - m_name = xml["name"].text(); - m_images = images( xml ); -} - - -QMap //private -Artist::params( const QString& method ) const -{ - QMap map; - map["method"] = "artist."+method; - map["artist"] = m_name; - return map; -} - - -QNetworkReply* -Artist::share( const QStringList& recipients, const QString& message, bool isPublic ) const -{ - QMap map = params("share"); - map["recipient"] = recipients.join(","); - map["public"] = isPublic ? "1" : "0"; - if (message.size()) map["message"] = message; - return lastfm::ws::post(map); -} - - -QUrl -Artist::www() const -{ - return UrlBuilder( "music" ).slash( Artist::name() ).url(); -} - -QNetworkReply* -Artist::getEvents(int limit) const -{ - QMap map = params("getEvents"); - if (limit) map["limit"] = QString::number(limit); - return ws::get( map ); -} - -QNetworkReply* -Artist::getInfo() const -{ - QMap map = params("getInfo"); - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - return ws::get( map ); -} - - -QNetworkReply* -Artist::getTags() const -{ - return ws::get( params("getTags") ); -} - -QNetworkReply* -Artist::getTopTags() const -{ - return ws::get( params("getTopTags") ); -} - - -QNetworkReply* -Artist::getTopTracks() const -{ - return ws::get( params("getTopTracks") ); -} - - -QNetworkReply* -Artist::getSimilar( int limit ) const -{ - QMap map = params("getSimilar"); - if ( limit != -1 ) map["limit"] = QString::number( limit ); - return ws::get( map ); -} - - -QNetworkReply* -Artist::search( int limit ) const -{ - QMap map = params("search"); - if (limit > 0) map["limit"] = QString::number(limit); - return ws::get(map); -} - - -QMap /* static */ -Artist::getSimilar( QNetworkReply* r ) -{ - QMap artists; - try - { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery e, lfm.children( "artist" )) - { - // convert floating percentage to int in range 0 to 10,000 - int const match = e["match"].text().toFloat() * 100; - artists.insertMulti( match, e["name"].text() ); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return artists; -} - - -QStringList /* static */ -Artist::getTopTracks( QNetworkReply* r ) -{ - QStringList tracks; - try - { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery e, lfm.children( "track" )) - { - tracks << e["name"].text(); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return tracks; -} - - -QList /* static */ -Artist::list( QNetworkReply* r ) -{ - QList artists; - try { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery xq, lfm.children( "artist" )) { - Artist artist( xq ); - artists += artist; - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return artists; -} - - -Artist -Artist::getInfo( QNetworkReply* r ) -{ - try { - XmlQuery lfm = r->readAll(); - Artist artist = lfm["artist"]["name"].text(); - artist.m_images = images( lfm["artist"] ); - return artist; - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - return Artist(); - } -} - - -QNetworkReply* -Artist::addTags( const QStringList& tags ) const -{ - if (tags.isEmpty()) - return 0; - QMap map = params("addTags"); - map["tags"] = tags.join( QChar(',') ); - return ws::post(map); -} diff --git a/thirdparty/liblastfm2/src/types/Artist.h b/thirdparty/liblastfm2/src/types/Artist.h deleted file mode 100644 index f84fcce39..000000000 --- a/thirdparty/liblastfm2/src/types/Artist.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole, Doug Mansell and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_ARTIST_H -#define LASTFM_ARTIST_H - -#include -#include -#include - -#include -#include - - -namespace lastfm -{ - class LASTFM_DLLEXPORT Artist : public AbstractType - { - private: - QString m_name; - QList m_images; - - public: - Artist() : AbstractType() - {} - - Artist( const QString& name ) : AbstractType(), m_name( name ) - {} - - Artist( const class XmlQuery& xml ); - - /** will be QUrl() unless you got this back from a getInfo or something call */ - QUrl imageUrl( ImageSize size = Large, bool square = false ) const; - - bool isNull() const { return m_name.isEmpty(); } - - /** the url for this artist's page at www.last.fm */ - QUrl www() const; - - Artist& operator=( const Artist& that ) { m_name = that.name(); m_images = that.m_images; return *this; } - bool operator==( const Artist& that ) const { return m_name == that.m_name; } - bool operator!=( const Artist& that ) const { return m_name != that.m_name; } - bool operator<( const Artist& that ) const { return m_name < that.m_name; } - - operator QString() const - { - /** if no artist name is set, return the musicbrainz unknown identifier - * in case some part of the GUI tries to display it anyway. Note isNull - * returns false still. So you should have queried that! */ - return m_name.isEmpty() ? "[unknown]" : m_name; - } - - QString toString() const { return name(); } - QString name() const { return QString(*this); } - - QDomElement toDomElement( QDomDocument& ) const { return QDomElement(); } - - QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; - - QNetworkReply* getEvents(int limit = 0) const; - QNetworkReply* getInfo() const; - static Artist getInfo( QNetworkReply* ); - - QNetworkReply* getSimilar( int limit = -1 ) const; - /** The match percentage is returned from last.fm as a 4 significant - * figure floating point value. So we multply it by 100 to make an - * integer in the range of 0 to 10,000. This is possible confusing - * for you, but I felt it best not to lose any precision, and floats - * aren't much fun. */ - static QMap getSimilar( QNetworkReply* ); - - /** use Tag::list to get the tag list out of the finished reply */ - QNetworkReply* getTags() const; - QNetworkReply* getTopTags() const; - - QNetworkReply* getTopTracks() const; - static QStringList getTopTracks( QNetworkReply* ); - - /** Last.fm dictates that you may submit at most 10 of these */ - QNetworkReply* addTags( const QStringList& ) const; - - QNetworkReply* search( int limit = -1 ) const; - static QList list( QNetworkReply* ); - - QMap params( const QString& method ) const; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/FingerprintId.cpp b/thirdparty/liblastfm2/src/types/FingerprintId.cpp deleted file mode 100644 index b201534a0..000000000 --- a/thirdparty/liblastfm2/src/types/FingerprintId.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "FingerprintId.h" -#include "../ws/ws.h" -#include -#include - - -QNetworkReply* -lastfm::FingerprintId::getSuggestions() const -{ - if (isNull()) return 0; - - QUrl const url( "http://ws.audioscrobbler.com/fingerprint/" + QString(*this) + ".xml" ); - QNetworkRequest const request( url ); - return lastfm::nam()->get( request ); -} - - -QMap //static -lastfm::FingerprintId::getSuggestions( QNetworkReply* reply ) -{ - QDomDocument xml; - xml.setContent( reply->readAll() ); - QDomNodeList nodes = xml.documentElement().elementsByTagName( "track" ); - - QMap tracks; - for (int x = 0; x < nodes.count(); ++x) - { - QDomElement const e = nodes.at(x).toElement(); - - MutableTrack t; - t.setTitle( e.firstChildElement( "title" ).text() ); - t.setArtist( e.firstChildElement( "artist" ).text() ); - tracks.insert( e.attribute( "confidence", "0.0" ).toFloat(), t ); - } - return tracks; -} diff --git a/thirdparty/liblastfm2/src/types/FingerprintId.h b/thirdparty/liblastfm2/src/types/FingerprintId.h deleted file mode 100644 index 5028c7736..000000000 --- a/thirdparty/liblastfm2/src/types/FingerprintId.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_FINGERPRINT_ID_H -#define LASTFM_FINGERPRINT_ID_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT FingerprintId - { - int id; - - public: - FingerprintId() : id( -1 ) - {} - - FingerprintId( uint i ) : id( i ) - {} - - bool isNull() const { return id == -1; } - - /** we query Last.fm for suggested metadata, how awesome is that? - * @returns null if isNull() */ - QNetworkReply* getSuggestions() const; - static QMap getSuggestions( QNetworkReply* ); - - /** -1 if you need to generate it */ - operator int() const { return id; } - /** isEmpty() if you need to generate it */ - operator QString() const { return id == -1 ? "" : QString::number( id ); } - }; -} - - -inline QDebug operator<<( QDebug d, lastfm::FingerprintId id) -{ - if (id.isNull()) - return d << "(null)"; - else - return d << int(id); -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Mbid.cpp b/thirdparty/liblastfm2/src/types/Mbid.cpp deleted file mode 100644 index 1ce1d90c5..000000000 --- a/thirdparty/liblastfm2/src/types/Mbid.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Mbid.h" -#include "mbid_mp3.c" -#include - -namespace lastfm -{ - Mbid //static - Mbid::fromLocalFile( const QString& path ) - { - char out[MBID_BUFFER_SIZE]; - QByteArray const bytes = QFile::encodeName( path ); - int const r = getMP3_MBID( bytes.data(), out ); - Mbid mbid; - if (r == 0) mbid.id = QString::fromLatin1( out ); - return mbid; - } -} diff --git a/thirdparty/liblastfm2/src/types/Mbid.h b/thirdparty/liblastfm2/src/types/Mbid.h deleted file mode 100644 index 071d4d1fc..000000000 --- a/thirdparty/liblastfm2/src/types/Mbid.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_MBID_H -#define LASTFM_MBID_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Mbid - { - QString id; - - public: - explicit Mbid( const QString& p = "" ) : id( p ) - {} - - bool isNull() const { return id.isNull() || id.isEmpty(); } - operator QString() const { return id; } - - /** if this is not an mp3 file you will be wasting time, as it won't work - * but we will do what you say anyway because you are the boss */ - static Mbid fromLocalFile( const QString& path ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Playlist.cpp b/thirdparty/liblastfm2/src/types/Playlist.cpp deleted file mode 100644 index 807da1c6a..000000000 --- a/thirdparty/liblastfm2/src/types/Playlist.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Playlist.h" -#include "Track.h" -#include "../ws/ws.h" - - -QNetworkReply* -lastfm::Playlist::addTrack( const Track& t ) const -{ - QMap map; - map["method"] = "playlist.addTrack"; - map["playlistID"] = m_id; - map["artist"] = t.artist(); - map["track"] = t.title(); - return lastfm::ws::post(map); -} - - -QNetworkReply* -lastfm::Playlist::fetch() const -{ - return fetch( QUrl("lastfm://playlist/" + QString::number( m_id )) ); -} - - -QNetworkReply* //static -lastfm::Playlist::fetch( const QUrl& url ) -{ - QMap map; - map["method"] = "playlist.fetch"; - map["playlistURL"] = url.toString(); - return lastfm::ws::get(map); -} - - -QNetworkReply* //static -lastfm::Playlist::create( const QString& title, const QString& description /*=""*/ ) -{ - QMap map; - map["method"] = "playlist.create"; - map["title"] = title; - if (description.size()) - map["description"] = description; - return lastfm::ws::post(map); -} diff --git a/thirdparty/liblastfm2/src/types/Playlist.h b/thirdparty/liblastfm2/src/types/Playlist.h deleted file mode 100644 index 89ee42ce6..000000000 --- a/thirdparty/liblastfm2/src/types/Playlist.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_PLAYLIST_H -#define LASTFM_PLAYLIST_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Playlist - { - int m_id; - - Playlist() : m_id( -1 ) - {} - - public: - Playlist( int id ) : m_id( id ) - {} - - int id() const { return m_id; } - - QNetworkReply* addTrack( const Track& ) const; - QNetworkReply* fetch() const; - - static QNetworkReply* create( const QString& title, const QString& description = "" ); - static QNetworkReply* fetch( const QUrl& url ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Tag.cpp b/thirdparty/liblastfm2/src/types/Tag.cpp deleted file mode 100644 index 675a147c7..000000000 --- a/thirdparty/liblastfm2/src/types/Tag.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Tag.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" -using lastfm::Tag; -using lastfm::User; - - -QUrl -Tag::www() const -{ - return UrlBuilder( "tag" ).slash( m_name ).url(); -} - - -QUrl -Tag::www( const User& user ) const -{ - return UrlBuilder( "user" ).slash( user.name() ).slash( "tags" ).slash( Tag::name() ).url(); -} - - -QNetworkReply* -Tag::search() const -{ - QMap map; - map["method"] = "tag.search"; - map["tag"] = m_name; - return ws::get(map); -} - -//static -QNetworkReply* -Tag::getTopTags() -{ - QMap map; - map["method"] = "tag.getTopTags"; - return ws::get(map); -} - -QMap //static -Tag::list( QNetworkReply* r ) -{ - QMap tags; - try { - foreach (XmlQuery xq, XmlQuery( r->readAll() ).children("tag")) - // we toLower always as otherwise it is ugly mixed case, as first - // ever tag decides case, and Last.fm is case insensitive about it - // anyway - tags.insertMulti( xq["count"].text().toInt(), xq["name"].text().toLower() ); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return tags; -} diff --git a/thirdparty/liblastfm2/src/types/Tag.h b/thirdparty/liblastfm2/src/types/Tag.h deleted file mode 100644 index 917faf1df..000000000 --- a/thirdparty/liblastfm2/src/types/Tag.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_TAG_H -#define LASTFM_TAG_H - -#include -#include -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Tag - { - QString m_name; - - public: - Tag( const QString& name ) : m_name( name ) - {} - - operator QString() const { return m_name; } - QString name() const { return m_name; } - - lastfm::Tag operator=( const Tag& that ) const { return Tag( that.name() ); } - bool operator<( const Tag& that ) const { return this->m_name < that.m_name; } - - /** the global tag page at www.last.fm */ - QUrl www() const; - /** the tag page for user @p user at www.last.fm */ - QUrl www( const class User& user ) const; - /** pass the finished QNetworkReply to Tag::list() */ - class QNetworkReply* search() const; - - /** the top global tags on Last.fm, sorted by popularity (number of times used) */ - static class QNetworkReply* getTopTags(); - - /** the integer is the weighting, not all list type return requests - * have a weighting, so the int may just be zero, if you don't care - * about the weight just do this: - * QStringList tags = Tag::list( reply ).values(); - */ - static QMap list( QNetworkReply* ); - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Tasteometer.cpp b/thirdparty/liblastfm2/src/types/Tasteometer.cpp deleted file mode 100644 index 5ec0e58a2..000000000 --- a/thirdparty/liblastfm2/src/types/Tasteometer.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Tasteometer.h" - -#include "lastfm.h" - -lastfm::Tasteometer::Tasteometer() -{ -} - - -QNetworkReply* -lastfm::Tasteometer::compare( const User& left, const User& right ) -{ - QMap map; - map["method"] = "Tasteometer.compare"; - map["type1"] = "user"; - map["value1"] = left.name(); - map["type2"] = "user"; - map["value2"] = right.name(); - return lastfm::ws::get( map ); -} diff --git a/thirdparty/liblastfm2/src/types/Tasteometer.h b/thirdparty/liblastfm2/src/types/Tasteometer.h deleted file mode 100644 index ef691b8f6..000000000 --- a/thirdparty/liblastfm2/src/types/Tasteometer.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TASTEOMETER_H -#define TASTEOMETER_H - -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Tasteometer - { - public: - Tasteometer(); - - public: - static QNetworkReply* compare( const User& left, const User& right ); - }; -} - -#endif // TASTEOMETER_H diff --git a/thirdparty/liblastfm2/src/types/Track.cpp b/thirdparty/liblastfm2/src/types/Track.cpp deleted file mode 100644 index 10cc41230..000000000 --- a/thirdparty/liblastfm2/src/types/Track.cpp +++ /dev/null @@ -1,653 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include -#include - -#include "Track.h" -#include "User.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include "../ws/ws.h" - - -lastfm::TrackContext::TrackContext() - :m_type( Unknown ) -{ - -} - -lastfm::TrackContext::TrackContext( const QString& type, const QList& values ) - :m_type( getType( type ) ), m_values( values ) -{ -} - -lastfm::TrackContext::Type -lastfm::TrackContext::getType( const QString& typeString ) -{ - Type type = Unknown; - - if ( typeString == "artist" ) - type = Artist; - else if ( typeString == "user" ) - type = User; - else if ( typeString == "neighbour" ) - type = Neighbour; - else if ( typeString == "friend" ) - type = Friend; - - return type; -} - -lastfm::TrackContext::Type -lastfm::TrackContext::type() const -{ - return m_type; -} - - -QList -lastfm::TrackContext::values() const -{ - return m_values; -} - - -lastfm::TrackData::TrackData() - : trackNumber( 0 ), - duration( 0 ), - source( Track::Unknown ), - rating( 0 ), - fpid( -1 ), - loved( false ), - scrobbleStatus( Track::Null ), - scrobbleError( Track::None ), - null( false ) -{} - -lastfm::Track::Track() - :AbstractType() -{ - d = new TrackData; - d->null = true; -} - -lastfm::Track::Track( const QDomElement& e ) - :AbstractType() -{ - d = new TrackData; - - if (e.isNull()) { d->null = true; return; } - - // XML response may have changed - QDomNode artistName = e.namedItem( "artist" ).namedItem( "name" ); - if( artistName.isNull() ) { - d->artist = e.namedItem( "artist" ).toElement().text(); - } else { - d->artist = artistName.toElement().text(); - - } - // XML response may have changed - QDomNode trackTitle = e.namedItem( "name" ); - if( trackTitle.isNull() ) - d->title = e.namedItem( "track" ).toElement().text(); - else - d->title = trackTitle.toElement().text(); - - - d->albumArtist = e.namedItem( "albumArtist" ).toElement().text(); - d->album = e.namedItem( "album" ).toElement().text(); - d->correctedArtist = e.namedItem( "correctedArtist" ).toElement().text(); - d->correctedAlbumArtist = e.namedItem( "correctedAlbumArtist" ).toElement().text(); - d->correctedAlbum = e.namedItem( "correctedAlbum" ).toElement().text(); - d->correctedTitle = e.namedItem( "correctedTrack" ).toElement().text(); - d->trackNumber = 0; - d->duration = e.namedItem( "duration" ).toElement().text().toInt(); - d->url = e.namedItem( "url" ).toElement().text(); - d->rating = e.namedItem( "rating" ).toElement().text().toUInt(); - d->source = e.namedItem( "source" ).toElement().text().toInt(); //defaults to 0, or lastfm::Track::Unknown - d->time = QDateTime::fromTime_t( e.namedItem( "timestamp" ).toElement().text().toUInt() ); - d->loved = e.namedItem( "loved" ).toElement().text().toInt(); - d->scrobbleStatus = e.namedItem( "scrobbleStatus" ).toElement().text().toInt(); - d->scrobbleError = e.namedItem( "scrobbleError" ).toElement().text().toInt(); - - for (QDomElement image(e.firstChildElement("image")) ; !image.isNull() ; image = e.nextSiblingElement("image")) - { - d->m_images[static_cast(image.attribute("size").toInt())] = image.text(); - } - - QDomNodeList nodes = e.namedItem( "extras" ).childNodes(); - for (int i = 0; i < nodes.count(); ++i) - { - QDomNode n = nodes.at(i); - QString key = n.nodeName(); - d->extras[key] = n.toElement().text(); - } -} - -void -lastfm::TrackData::onLoveFinished() -{ - try - { - XmlQuery lfm = static_cast(sender())->readAll(); - if ( lfm.attribute( "status" ) == "ok") - loved = true; - - } - catch (...) - { - } - emit loveToggled( loved ); -} - - -void -lastfm::TrackData::onUnloveFinished() -{ - try - { - XmlQuery lfm = static_cast(sender())->readAll(); - if ( lfm.attribute( "status" ) == "ok") - loved = false; - } - catch (...) - { - } - - emit loveToggled( loved ); -} - -void -lastfm::TrackData::onGotInfo() -{ - const QByteArray data = static_cast(sender())->readAll(); - - try - { - lastfm::XmlQuery lfm( data ); - - QString imageUrl = lfm["track"]["image size=small"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Small] = imageUrl; - imageUrl = lfm["track"]["image size=medium"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Medium] = imageUrl; - imageUrl = lfm["track"]["image size=large"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Large] = imageUrl; - imageUrl = lfm["track"]["image size=extralarge"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::ExtraLarge] = imageUrl; - imageUrl = lfm["track"]["image size=mega"].text(); - if ( !imageUrl.isEmpty() ) m_images[lastfm::Mega] = imageUrl; - - loved = lfm["track"]["userloved"].text().toInt(); - - emit gotInfo( data ); - emit loveToggled( loved ); - } - catch (...) - { - emit gotInfo( data ); - } - - // you should connect everytime you call getInfo - disconnect( this, SIGNAL(gotInfo(const QByteArray&)), 0, 0); -} - - -QDomElement -lastfm::Track::toDomElement( QDomDocument& xml ) const -{ - QDomElement item = xml.createElement( "track" ); - - #define makeElement( tagname, getter ) { \ - QString v = getter; \ - if (!v.isEmpty()) \ - { \ - QDomElement e = xml.createElement( tagname ); \ - e.appendChild( xml.createTextNode( v ) ); \ - item.appendChild( e ); \ - } \ - } - - makeElement( "artist", d->artist ); - makeElement( "albumArtist", d->albumArtist ); - makeElement( "album", d->album ); - makeElement( "track", d->title ); - makeElement( "correctedArtist", d->correctedArtist ); - makeElement( "correctedAlbumArtist", d->correctedAlbumArtist ); - makeElement( "correctedAlbum", d->correctedAlbum ); - makeElement( "correctedTrack", d->correctedTitle ); - makeElement( "duration", QString::number( d->duration ) ); - makeElement( "timestamp", QString::number( d->time.toTime_t() ) ); - makeElement( "url", d->url.toString() ); - makeElement( "source", QString::number( d->source ) ); - makeElement( "rating", QString::number(d->rating) ); - makeElement( "fpId", QString::number(d->fpid) ); - makeElement( "mbId", mbid() ); - makeElement( "loved", QString::number( isLoved() ) ); - makeElement( "scrobbleStatus", QString::number( scrobbleStatus() ) ); - makeElement( "scrobbleError", QString::number( scrobbleError() ) ); - - // put the images urls in the dom - QMapIterator imageIter( d->m_images ); - while (imageIter.hasNext()) { - QDomElement e = xml.createElement( "image" ); - e.appendChild( xml.createTextNode( imageIter.next().value().toString() ) ); - e.setAttribute( "size", imageIter.key() ); - item.appendChild( e ); - } - - // add the extras to the dom - QDomElement extras = xml.createElement( "extras" ); - QMapIterator extrasIter( d->extras ); - while (extrasIter.hasNext()) { - QDomElement e = xml.createElement( extrasIter.next().key() ); - e.appendChild( xml.createTextNode( extrasIter.value() ) ); - extras.appendChild( e ); - } - item.appendChild( extras ); - - return item; -} - - -bool -lastfm::Track::corrected() const -{ - // If any of the corrected string have been set and they are different - // from the initial strings then this track has been corrected. - return ( (!d->correctedTitle.isEmpty() && (d->correctedTitle != d->title)) - || (!d->correctedAlbum.isEmpty() && (d->correctedAlbum != d->album)) - || (!d->correctedArtist.isEmpty() && (d->correctedArtist != d->artist)) - || (!d->correctedAlbumArtist.isEmpty() && (d->correctedAlbumArtist != d->albumArtist))); -} - -lastfm::Artist -lastfm::Track::artist( Corrections corrected ) const -{ - if ( corrected == Corrected && !d->correctedArtist.isEmpty() ) - return Artist( d->correctedArtist ); - - return Artist( d->artist ); -} - -lastfm::Artist -lastfm::Track::albumArtist( Corrections corrected ) const -{ - if ( corrected == Corrected && !d->correctedAlbumArtist.isEmpty() ) - return Artist( d->correctedAlbumArtist ); - - return Artist( d->albumArtist ); -} - -lastfm::Album -lastfm::Track::album( Corrections corrected ) const -{ - if ( corrected == Corrected && !d->correctedAlbum.isEmpty() ) - return Album( artist( corrected ), d->correctedAlbum ); - - return Album( artist( corrected ), d->album ); -} - -QString -lastfm::Track::title( Corrections corrected ) const -{ - /** if no title is set, return the musicbrainz unknown identifier - * in case some part of the GUI tries to display it anyway. Note isNull - * returns false still. So you should have queried this! */ - - if ( corrected == Corrected && !d->correctedTitle.isEmpty() ) - return d->correctedTitle; - - return d->title.isEmpty() ? "[unknown]" : d->title; -} - - -QUrl -lastfm::Track::imageUrl( lastfm::ImageSize size, bool square ) const -{ - if( !square ) return d->m_images.value( size ); - - QUrl url = d->m_images.value( size ); - QRegExp re( "/serve/(\\d*)s?/" ); - return QUrl( url.toString().replace( re, "/serve/\\1s/" )); -} - - -QString -lastfm::Track::toString( const QChar& separator, Corrections corrections ) const -{ - if ( d->artist.isEmpty() ) - { - if ( d->title.isEmpty() ) - return QFileInfo( d->url.path() ).fileName(); - else - return title( corrections ); - } - - if ( d->title.isEmpty() ) - return artist( corrections ); - - return artist( corrections ) + ' ' + separator + ' ' + title( corrections ); -} - - -QString //static -lastfm::Track::durationString( int const duration ) -{ - QTime t = QTime().addSecs( duration ); - if (duration < 60*60) - return t.toString( "m:ss" ); - else - return t.toString( "hh:mm:ss" ); -} - - -QNetworkReply* -lastfm::Track::share( const QStringList& recipients, const QString& message, bool isPublic ) const -{ - QMap map = params("share"); - map["recipient"] = recipients.join(","); - map["public"] = isPublic ? "1" : "0"; - if (message.size()) map["message"] = message; - return ws::post(map); -} - - -void -lastfm::Track::invalidateGetInfo() -{ - // invalidate the track.getInfo cache - QAbstractNetworkCache* cache = lastfm::nam()->cache(); - if ( cache ) - { - QMap map = params("getInfo", true); - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - cache->remove( lastfm::ws::url( map ) ); - } -} - - -void -lastfm::MutableTrack::setFromLfm( const XmlQuery& lfm ) -{ - QString imageUrl = lfm["track"]["image size=small"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Small] = imageUrl; - imageUrl = lfm["track"]["image size=medium"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Medium] = imageUrl; - imageUrl = lfm["track"]["image size=large"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Large] = imageUrl; - imageUrl = lfm["track"]["image size=extralarge"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::ExtraLarge] = imageUrl; - imageUrl = lfm["track"]["image size=mega"].text(); - if ( !imageUrl.isEmpty() ) d->m_images[lastfm::Mega] = imageUrl; - - d->loved = lfm["track"]["userloved"].text().toInt(); - - d->forceLoveToggled( d->loved ); -} - -void -lastfm::MutableTrack::setImageUrl( lastfm::ImageSize size, const QString& url ) -{ - d->m_images[size] = url; -} - - -void -lastfm::MutableTrack::love() -{ - QNetworkReply* reply = ws::post(params("love")); - QObject::connect( reply, SIGNAL(finished()), signalProxy(), SLOT(onLoveFinished())); - - invalidateGetInfo(); -} - - -void -lastfm::MutableTrack::unlove() -{ - QNetworkReply* reply = ws::post(params("unlove")); - QObject::connect( reply, SIGNAL(finished()), signalProxy(), SLOT(onUnloveFinished())); - - invalidateGetInfo(); -} - -QNetworkReply* -lastfm::MutableTrack::ban() -{ - d->extras["rating"] = "B"; - return ws::post(params("ban")); -} - - -QMap -lastfm::Track::params( const QString& method, bool use_mbid ) const -{ - QMap map; - map["method"] = "Track."+method; - if (d->mbid.size() && use_mbid) - map["mbid"] = d->mbid; - else { - map["artist"] = d->artist; - map["track"] = d->title; - } - return map; -} - - -QNetworkReply* -lastfm::Track::getSimilar( int limit ) const -{ - QMap map = params("getSimilar"); - if ( limit != -1 ) map["limit"] = QString::number( limit ); - map["autocorrect"] = "1"; - return ws::get( map ); -} - - -QMap > /* static */ -lastfm::Track::getSimilar( QNetworkReply* r ) -{ - QMap > tracks; - try - { - QByteArray b = r->readAll(); - XmlQuery lfm = b; - foreach (XmlQuery e, lfm.children( "track" )) - { - QPair< QString, QString > track; - track.first = e["name"].text(); - - XmlQuery artist = e.children( "artist" ).first(); - track.second = artist["name"].text(); - - // convert floating percentage to int in range 0 to 10,000 - int const match = e["match"].text().toFloat() * 100; - tracks.insertMulti( match, track ); - } - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - - return tracks; -} - - -QNetworkReply* -lastfm::Track::getTopTags() const -{ - return ws::get( params("getTopTags", true) ); -} - - -QNetworkReply* -lastfm::Track::getTopFans() const -{ - return ws::get( params("getTopFans", true) ); -} - - -QNetworkReply* -lastfm::Track::getTags() const -{ - return ws::get( params("getTags", true) ); -} - -void -lastfm::Track::getInfo() const -{ - QMap map = params("getInfo", true); - if (!lastfm::ws::Username.isEmpty()) map["username"] = lastfm::ws::Username; - if (!lastfm::ws::SessionKey.isEmpty()) map["sk"] = lastfm::ws::SessionKey; - QObject::connect( ws::get( map ), SIGNAL(finished()), d.data(), SLOT(onGotInfo())); -} - - -QNetworkReply* -lastfm::Track::getBuyLinks( const QString& country ) const -{ - QMap map = params( "getBuyLinks", true ); - map["country"] = country; - return ws::get( map ); -} - - -QNetworkReply* -lastfm::Track::addTags( const QStringList& tags ) const -{ - if (tags.isEmpty()) - return 0; - QMap map = params("addTags"); - map["tags"] = tags.join( QChar(',') ); - return ws::post(map); -} - - -QNetworkReply* -lastfm::Track::removeTag( const QString& tag ) const -{ - if (tag.isEmpty()) - return 0; - QMap map = params( "removeTag" ); - map["tags"] = tag; - return ws::post(map); -} - - -QNetworkReply* -lastfm::Track::updateNowPlaying() const -{ - return updateNowPlaying(duration()); -} - -QNetworkReply* -lastfm::Track::updateNowPlaying( int duration ) const -{ - QMap map = params("updateNowPlaying"); - map["duration"] = QString::number( duration ); - if ( !album().isNull() ) map["album"] = album(); - map["context"] = extra("playerId"); - - qDebug() << map; - - return ws::post(map); -} - -QNetworkReply* -lastfm::Track::removeNowPlaying() const -{ - QMap map; - map["method"] = "track.removeNowPlaying"; - - qDebug() << map; - - return ws::post(map); -} - - -QNetworkReply* -lastfm::Track::scrobble() const -{ - QMap map = params("scrobble"); - map["duration"] = QString::number( d->duration ); - map["timestamp"] = QString::number( d->time.toTime_t() ); - map["context"] = extra("playerId"); - map["albumArtist"] = d->albumArtist; - if ( !d->album.isEmpty() ) map["album"] = d->album; - - qDebug() << map; - - return ws::post(map); -} - -QNetworkReply* -lastfm::Track::scrobble(const QList& tracks) -{ - QMap map; - map["method"] = "track.scrobble"; - - for ( int i(0) ; i < tracks.count() ; ++i ) - { - map["duration[" + QString::number(i) + "]"] = QString::number( tracks[i].duration() ); - map["timestamp[" + QString::number(i) + "]"] = QString::number( tracks[i].timestamp().toTime_t() ); - map["track[" + QString::number(i) + "]"] = tracks[i].title(); - map["context[" + QString::number(i) + "]"] = tracks[i].extra("playerId"); - if ( !tracks[i].album().isNull() ) map["album[" + QString::number(i) + "]"] = tracks[i].album(); - map["artist[" + QString::number(i) + "]"] = tracks[i].artist(); - map["albumArtist[" + QString::number(i) + "]"] = tracks[i].albumArtist(); - if ( !tracks[i].mbid().isNull() ) map["mbid[" + QString::number(i) + "]"] = tracks[i].mbid(); - } - - qDebug() << map; - - return ws::post(map); -} - - -QUrl -lastfm::Track::www() const -{ - return UrlBuilder( "music" ).slash( artist( Corrected ) ).slash( album( Corrected ).isNull() ? QString("_") : album( Corrected )).slash( title( Corrected ) ).url(); -} - - -bool -lastfm::Track::isMp3() const -{ - //FIXME really we should check the file header? - return d->url.scheme() == "file" && - d->url.path().endsWith( ".mp3", Qt::CaseInsensitive ); -} - -void -lastfm::MutableTrack::setCorrections( QString title, QString album, QString artist, QString albumArtist ) -{ - d->correctedTitle = title; - d->correctedAlbum = album; - d->correctedArtist = artist; - d->correctedAlbumArtist = albumArtist; - - d->forceCorrected( toString() ); -} - diff --git a/thirdparty/liblastfm2/src/types/Track.h b/thirdparty/liblastfm2/src/types/Track.h deleted file mode 100644 index 4fa0c7043..000000000 --- a/thirdparty/liblastfm2/src/types/Track.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole, Doug Mansell and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_TRACK_H -#define LASTFM_TRACK_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace lastfm { - -class LASTFM_DLLEXPORT TrackContext -{ -public: - enum Type - { - Unknown, - User, - Friend, - Neighbour, - Artist - }; - - TrackContext(); - TrackContext( const QString& type, const QList& values ); - - Type type() const; - QList values() const; -private: - static Type getType( const QString& type ); - -private: - Type m_type; - QList m_values; -}; - -class TrackData : public QObject, public QSharedData -{ - Q_OBJECT - - friend class Track; - friend class MutableTrack; -public: - TrackData(); - -public: - QString artist; - QString albumArtist; - QString album; - QString title; - QString correctedArtist; - QString correctedAlbumArtist; - QString correctedAlbum; - QString correctedTitle; - TrackContext context; - uint trackNumber; - uint duration; - short source; - short rating; - QString mbid; /// musicbrainz id - uint fpid; - QUrl url; - QDateTime time; /// the time the track was started at - bool loved; - QMap m_images; - short scrobbleStatus; - short scrobbleError; - QString scrobbleErrorText; - - //FIXME I hate this, but is used for radio trackauth etc. - QMap extras; - - bool null; - -private: - void forceLoveToggled( bool love ) { emit loveToggled( love );} - void forceScrobbleStatusChanged() { emit scrobbleStatusChanged(); } - void forceCorrected( QString correction ) { emit corrected( correction ); } - -private slots: - void onLoveFinished(); - void onUnloveFinished(); - void onGotInfo(); - -signals: - void loveToggled( bool love ); - void loveFinished(); - void unlovedFinished(); - void gotInfo( const QByteArray& ); - void scrobbleStatusChanged(); - void corrected( QString correction ); -}; - - -/** Our track type. It's quite good, you may want to use it as your track type - * in general. It is explicitly shared. Which means when you make a copy, they - * both point to the same data still. This is like Qt's implicitly shared - * classes, eg. QString, however if you mod a copy of a QString, the copy - * detaches first, so then you have two copies. Our Track object doesn't - * detach, which is very handy for our usage in the client, but perhaps not - * what you want. If you need a deep copy for eg. work in a thread, call - * clone(). */ -class LASTFM_DLLEXPORT Track : public AbstractType -{ -public: - friend class TrackSignalProxy; - - enum Source - { - // DO NOT UNDER ANY CIRCUMSTANCES CHANGE THE ORDER OR VALUES OF THIS ENUM! - // you will cause broken settings and b0rked scrobbler cache submissions - - Unknown = 0, - LastFmRadio, - Player, - MediaDevice, - NonPersonalisedBroadcast, // eg Shoutcast, BBC Radio 1, etc. - PersonalisedRecommendation, // eg Pandora, but not Last.fm - }; - - enum ScrobbleStatus - { - Null = 0, - Cached, - Submitted, - Error - }; - - enum Corrections - { - Original = 0, - Corrected - }; - - enum ScrobbleError - { - None = 0, - FilteredArtistName = 113, - FilteredTrackName = 114, - FilteredAlbumName = 115, - FilteredTimestamp = 116, - ExceededMaxDailyScrobbles = 118, - InvalidStreamAuth = 119 - }; - - Track(); - explicit Track( const QDomElement& ); - - /** this track and that track point to the same object, so they are the same - * in fact. This doesn't do a deep data comparison. So even if all the - * fields are the same it will return false if they aren't in fact spawned - * from the same initial Track object */ - bool sameObject( const Track& that ) - { - return (this->d == that.d); - } - - bool operator==( const Track& that ) const - { - return ( this->title() == that.title() && - this->album() == that.album() && - this->artist() == that.artist()); - } - bool operator!=( const Track& that ) const - { - return !operator==( that ); - } - - QObject* signalProxy() const { return d.data(); } - - /** only a Track() is null */ - bool isNull() const { return d->null; } - - bool corrected() const; - - Artist artist( Corrections corrected = Original ) const; - Artist albumArtist( Corrections corrected = Original ) const; - Album album( Corrections corrected = Original ) const; - QString title( Corrections corrected = Original ) const; - - uint trackNumber() const { return d->trackNumber; } - uint duration() const { return d->duration; } /// in seconds - Mbid mbid() const { return Mbid(d->mbid); } - QUrl url() const { return d->url; } - QDateTime timestamp() const { return d->time; } - Source source() const { return static_cast(d->source); } - uint fingerprintId() const { return d->fpid; } - bool isLoved() const { return d->loved; } - QUrl imageUrl( lastfm::ImageSize size, bool square ) const; - - QString durationString() const { return durationString( d->duration ); } - static QString durationString( int seconds ); - - ScrobbleStatus scrobbleStatus() const { return static_cast(d->scrobbleStatus); } - ScrobbleError scrobbleError() const { return static_cast(d->scrobbleError); } - QString scrobbleErrorText() const { return d->scrobbleErrorText; } - - /** default separator is an en-dash */ - QString toString() const { return toString( Corrected ); } - QString toString( Corrections corrections ) const { return toString( QChar(8211), corrections );} - QString toString( const QChar& separator, Corrections corrections = Original ) const; - /** the standard representation of this object as an XML node */ - QDomElement toDomElement( class QDomDocument& ) const; - - TrackContext context() const { return d->context; } - - QString extra( const QString& key ) const{ return d->extras[ key ]; } - - bool operator<( const Track &that ) const - { - return this->d->time < that.d->time; - } - - bool isMp3() const; - - operator QVariant() const { return QVariant::fromValue( *this ); } - -//////////// lastfm::Ws - - /** See last.fm/api Track section */ - QNetworkReply* share( const QStringList& recipients, const QString& message = "", bool isPublic = true ) const; - - QNetworkReply* getSimilar( int limit = -1 ) const; - /** The match percentage is returned from last.fm as a 4 significant - * figure floating point value. So we multply it by 100 to make an - * integer in the range of 0 to 10,000. This is possible confusing - * for you, but I felt it best not to lose any precision, and floats - * aren't much fun. */ - static QMap > getSimilar( QNetworkReply* ); - - /** you can get any QNetworkReply TagList using Tag::list( QNetworkReply* ) */ - QNetworkReply* getTags() const; // for the logged in user - QNetworkReply* getTopTags() const; - QNetworkReply* getTopFans() const; - void getInfo() const; - QNetworkReply* getBuyLinks( const QString& country ) const; - - /** you can only add 10 tags, we submit everything you give us, but the - * docs state 10 only. Will return 0 if the list is empty. */ - QNetworkReply* addTags( const QStringList& ) const; - /** will return 0 if the string is "" */ - QNetworkReply* removeTag( const QString& ) const; - - /** scrobble the track */ - QNetworkReply* updateNowPlaying() const; - QNetworkReply* updateNowPlaying( int duration ) const; - QNetworkReply* removeNowPlaying() const; - QNetworkReply* scrobble() const; - static QNetworkReply* scrobble(const QList& tracks); - - /** the url for this track's page at last.fm */ - QUrl www() const; - -protected: - QExplicitlySharedDataPointer d; - QMap params( const QString& method, bool use_mbid = false ) const; - void invalidateGetInfo(); -private: - Track( TrackData* that_d ) : d( that_d ) - {} -}; - - - -/** This class allows you to change Track objects, it is easy to use: - * MutableTrack( some_track_object ).setTitle( "Arse" ); - * - * We have a separate MutableTrack class because in our usage, tracks - * only get mutated once, and then after that, very rarely. This pattern - * encourages such usage, which is generally sensible. You can feel more - * comfortable that the data hasn't accidently changed behind your back. - */ -class LASTFM_DLLEXPORT MutableTrack : public Track -{ -public: - MutableTrack() - { - d->null = false; - } - - /** NOTE that passing a Track() to this ctor will automatically make it non - * null. Which may not be what you want. So be careful - * Rationale: this is the most maintainable way to do it - */ - MutableTrack( const Track& that ) : Track( that ) - { - d->null = false; - } - - void setFromLfm( const XmlQuery& lfm ); - void setImageUrl( lastfm::ImageSize size, const QString& url ); - - void setArtist( QString artist ) { d->artist = artist.trimmed(); } - void setAlbumArtist( QString albumArtist ) { d->albumArtist = albumArtist.trimmed(); } - void setAlbum( QString album ) { d->album = album.trimmed(); } - void setTitle( QString title ) { d->title = title.trimmed(); } - void setCorrections( QString title, QString album, QString artist, QString albumArtist ); - void setTrackNumber( uint n ) { d->trackNumber = n; } - void setDuration( uint duration ) { d->duration = duration; } - void setUrl( QUrl url ) { d->url = url; } - void setSource( Source s ) { d->source = s; } - void setLoved( bool loved ) { d->loved = loved; } - - void setMbid( Mbid id ) { d->mbid = id; } - void setFingerprintId( uint id ) { d->fpid = id; } - - void setScrobbleStatus( ScrobbleStatus scrobbleStatus ) - { - d->scrobbleStatus = scrobbleStatus; - d->forceScrobbleStatusChanged(); - } - void setScrobbleError( ScrobbleError scrobbleError ) { d->scrobbleError = scrobbleError; } - void setScrobbleErrorText( const QString& scrobbleErrorText ) { d->scrobbleErrorText = scrobbleErrorText; } - - /** you also must scrobble this track for the love to become permenant */ - void love(); - void unlove(); - QNetworkReply* ban(); - - void stamp() { d->time = QDateTime::currentDateTime(); } - - void setExtra( const QString& key, const QString& value ) { d->extras[key] = value; } - void removeExtra( QString key ) { d->extras.remove( key ); } - void setTimeStamp( const QDateTime& dt ) { d->time = dt; } - - void setContext( TrackContext context ) { d->context = context;} -}; - - -} //namespace lastfm - - -inline QDebug operator<<( QDebug d, const lastfm::Track& t ) -{ - return !t.isNull() - ? d << t.toString( '-' ) << t.url() - : d << "Null Track object"; -} - - -Q_DECLARE_METATYPE( lastfm::Track ); - -#endif //LASTFM_TRACK_H diff --git a/thirdparty/liblastfm2/src/types/User.cpp b/thirdparty/liblastfm2/src/types/User.cpp deleted file mode 100644 index c19bf46ce..000000000 --- a/thirdparty/liblastfm2/src/types/User.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "User.h" -#include "Track.h" -#include "../core/UrlBuilder.h" -#include "../core/XmlQuery.h" -#include -#include -#include - -using lastfm::User; -using lastfm::UserList; -using lastfm::UserDetails; -using lastfm::XmlQuery; -using lastfm::ImageSize; - -User::User( const XmlQuery& xml ) - :AbstractType(), m_match( -1.0f ) -{ - m_name = xml["name"].text(); - m_images << xml["image size=small"].text() - << xml["image size=medium"].text() - << xml["image size=large"].text(); - m_realName = xml["realname"].text(); -} - - -QUrl -User::imageUrl( ImageSize size, bool square ) const -{ - if( !square ) return m_images.value( size ); - - QUrl url = m_images.value( size ); - QRegExp re( "/serve/(\\d*)s?/" ); - return QUrl( url.toString().replace( re, "/serve/\\1s/" )); -} - - -QMap -User::params(const QString& method) const -{ - QMap map; - map["method"] = "user."+method; - map["user"] = m_name; - return map; -} - - -QNetworkReply* -User::getFriends( bool recentTracks, int limit, int page ) const -{ - QMap map = params( "getFriends" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - if ( recentTracks ) map["recenttracks"] = "1"; - return ws::get( map ); -} - - -QNetworkReply* -User::getFriendsListeningNow( int limit, int page ) const -{ - QMap map = params( "getFriendsListeningNow" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getTopTags() const -{ - return ws::get( params( "getTopTags" ) ); -} - - -QNetworkReply* -User::getTopArtists( QString period, int limit, int page ) const -{ - QMap map = params( "getTopArtists" ); - map["period"] = period; - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getRecentArtists() const -{ - return ws::get( params( "getRecentArtists" ) ); -} - - -QNetworkReply* -User::getRecentTracks( int limit , int page ) const -{ - QMap map = params( "getRecentTracks" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - - QAbstractNetworkCache* cache = lastfm::nam()->cache(); - if ( cache ) - cache->remove( lastfm::ws::url( map ) ); - - return ws::get( map ); -} - -QNetworkReply* -User::getRecentStations( int limit, int page ) const -{ - QMap map = params( "getRecentStations" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getRecommendedArtists( int limit, int page ) const -{ - QMap map = params( "getRecommendedArtists" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getNeighbours( int limit, int page ) const -{ - QMap map = params( "getNeighbours" ); - map["limit"] = QString::number( limit ); - map["page"] = QString::number( page ); - return ws::get( map ); -} - - -QNetworkReply* -User::getPlaylists() const -{ - return ws::get( params( "getPlaylists" ) ); -} - - -UserList //static -User::list( QNetworkReply* r ) -{ - UserList users; - try { - XmlQuery lfm = r->readAll(); - foreach (XmlQuery e, lfm.children( "user" )) - { - User u( e ); - users += u; - } - - users.total = lfm["friends"].attribute("total").toInt(); - users.page = lfm["friends"].attribute("page").toInt(); - users.perPage = lfm["friends"].attribute("perPage").toInt(); - users.totalPages = lfm["friends"].attribute("totalPages").toInt(); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } - return users; -} - - -QNetworkReply* //static -UserDetails::getInfo( const QString& username ) -{ - QMap map; - map["method"] = "user.getInfo"; - map["user"] = username; - return ws::post( map ); -} - - - - -/* -QNetworkReply* //static -UserDetails::getRecommendedArtists() -{ - QMap map; - map["method"] = "user.getRecommendedArtists"; - return ws::post( map ); -} -*/ - -QUrl -User::www() const -{ - return UrlBuilder( "user" ).slash( m_name ).url(); -} - -UserDetails::UserDetails() - : User() - , m_age( 0 ) - , m_scrobbles( 0 ) - , m_registered( QDateTime() ) - , m_isSubscriber( false ) - , m_canBootstrap( false ) -{} - -UserDetails::UserDetails( QNetworkReply* reply ) -{ - try - { - XmlQuery user = XmlQuery( reply->readAll() )["user"]; - m_age = user["age"].text().toUInt(); - m_scrobbles = user["playcount"].text().toUInt(); - m_registered = QDateTime::fromTime_t(user["registered"].attribute("unixtime").toUInt()); - m_country = user["country"].text(); - m_isSubscriber = ( user["subscriber"].text() == "1" ); - m_canBootstrap = ( user["bootstrap"].text() == "1" ); - m_gender = user["gender"].text(); - m_realName = user["realname"].text(); - m_name = user["name"].text(); - m_images << user["image size=small"].text() - << user["image size=medium"].text() - << user["image size=large"].text(); - } - catch (ws::ParseError& e) - { - qWarning() << e.what(); - } -} - - -QString -UserDetails::getInfoString() const -{ - QString text; - - text = QObject::tr("%1").arg( m_realName.isEmpty() ? m_name : m_realName ); - if ( m_age ) text.append( QObject::tr(", %1").arg( m_age ) ); - if ( m_gender.known() ) text.append( QObject::tr(", %1").arg( m_gender.toString() ) ); - if ( !m_country.isEmpty() ) text.append( QObject::tr(", %1").arg( m_country ) ); - if ( m_scrobbles ) text.append( QObject::tr(", %L1 scrobbles").arg( m_scrobbles ) ); - - return text; -} - -void -UserDetails::setScrobbleCount( quint32 scrobbleCount ) -{ - m_scrobbles = scrobbleCount; -} - - -void -UserDetails::setDateRegistered( const QDateTime& date ) -{ - m_registered = date; -} - -void -UserDetails::setImages( const QList& images ) -{ - m_images = images; -} - -void -UserDetails::setRealName( const QString& realName ) -{ - m_realName = realName; -} -void -UserDetails::setAge( unsigned short age ) -{ - m_age = age; -} - -void -UserDetails::setIsSubscriber( bool subscriber ) -{ - m_isSubscriber = subscriber; -} - -void -UserDetails::setCanBootstrap( bool canBootstrap ) -{ - m_canBootstrap = canBootstrap; -} - -void -UserDetails::setGender( const QString& s ) -{ - m_gender = Gender( s ); -} - -void -UserDetails::setCountry( const QString& country ) -{ - m_country = country; -} - diff --git a/thirdparty/liblastfm2/src/types/User.h b/thirdparty/liblastfm2/src/types/User.h deleted file mode 100644 index 4c8adf08d..000000000 --- a/thirdparty/liblastfm2/src/types/User.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - Copyright 2009-2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole, Doug Mansell and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_USER_H -#define LASTFM_USER_H - -#include -#include -#include - -#include -#include - -namespace lastfm -{ - class UserList; - - class LASTFM_DLLEXPORT User : public AbstractType - { - public: - User() : AbstractType(), m_name( lastfm::ws::Username ), m_match( -1.0f ) - {} - - User( const QString& name ) : AbstractType(), m_name( name ), m_match( -1.0f ) - {} - - User( const class XmlQuery& xml ); - - lastfm::User& operator=( const lastfm::User& that ) { m_name = that.name(); m_images = that.m_images; m_realName = that.m_realName; m_match = that.m_match; return *this; } - bool operator==(const lastfm::User& that) const { return m_name == that.m_name; } - bool operator<(const lastfm::User& that) const { return m_name < that.m_name; } - - operator QString() const { return m_name; } - QString name() const { return m_name; } - void setName( const QString& name ){ m_name = name; } - - /** use Tag::list() on the response to get a WeightedStringList */ - QNetworkReply* getTopTags() const; - - /** use User::list() on the response to get a QList */ - QNetworkReply* getFriends( bool recentTracks = false, int limit = 50, int page = 1 ) const; - QNetworkReply* getFriendsListeningNow( int limit = 50, int page = 1 ) const; - QNetworkReply* getNeighbours( int limit = 50, int page = 1 ) const; - - QNetworkReply* getPlaylists() const; - QNetworkReply* getTopArtists( QString period = "overall", int limit = 50, int page = 1 ) const; - QNetworkReply* getRecentTracks( int limit = 50, int page = 1 ) const; - QNetworkReply* getRecentArtists() const; - QNetworkReply* getRecentStations( int limit = 10, int page = 1 ) const; - QNetworkReply* getRecommendedArtists( int limit = 50, int page = 1 ) const; - - static UserList list( QNetworkReply* ); - - QString toString() const { return name(); } - QDomElement toDomElement( QDomDocument& ) const { return QDomElement(); } - - ////// - QUrl imageUrl( ImageSize size = Large, bool square = false ) const; - - QString realName() const { return m_realName; } - - /** the user's profile page at www.last.fm */ - QUrl www() const; - - /** Returns the match between the logged in user and the user which this - * object represents (if < 0.0f then not set) */ - float match() const { return m_match; } - - protected: - QString m_name; - - QList m_images; - - float m_match; - - QString m_realName; - - QMap params( const QString& method ) const; - }; - - class LASTFM_DLLEXPORT Gender - { - QString s; - - public: - Gender() :s(/*confused!*/){} - - Gender( const QString& ss ) :s( ss.toLower() ) - {} - - bool known() const { return male() || female(); } - bool male() const { return s == "m"; } - bool female() const { return s == "f"; } - - QString toString() const - { - QString result; - - if (male()) - result = QObject::tr( "m" ); - else if (female()) - result = QObject::tr( "f" ); - else - result = QObject::tr( "n" ); // as in neuter - - return result; - } - }; - - - /** The Extended User contains extra information about a user's account */ - class LASTFM_DLLEXPORT UserDetails : public User - { - public: - UserDetails(); - /** User details */ - UserDetails( QNetworkReply* ); - - /** you can only get information about the any user */ - static QNetworkReply* getInfo( const QString& username = lastfm::ws::Username ); - - /** a verbose string, eg. "A man with 36,153 scrobbles" */ - QString getInfoString() const; - - bool isSubscriber() const{ return m_isSubscriber; } - bool canBootstrap() const{ return m_canBootstrap; } - quint32 scrobbleCount() const{ return m_scrobbles; } - QDateTime dateRegistered() const { return m_registered; } - Gender gender() const { return m_gender; } - QString country() const { return m_country; } - - void setScrobbleCount( quint32 scrobblesCount ); - void setDateRegistered( const QDateTime& date ); - void setImages( const QList& images ); - void setRealName( const QString& realName ); - void setAge( unsigned short age ); - void setIsSubscriber( bool subscriber ); - void setCanBootstrap( bool canBootstrap ); - void setGender( const QString& s ); - void setCountry( const QString& country ); - - - // pass the result to Artist::list(), if you want the other data - // you have to parse the lfm() yourself members - // http://www.last.fm/api/show?service=388 - // static QNetworkReply* getRecommendedArtists(); - - protected: - Gender m_gender; - unsigned short m_age; - unsigned int m_scrobbles; - QDateTime m_registered; - QString m_country; - bool m_isSubscriber; - bool m_canBootstrap; - }; - - class LASTFM_DLLEXPORT UserList : public QList - { - public: - int total; - int page; - int perPage; - int totalPages; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/Xspf.cpp b/thirdparty/liblastfm2/src/types/Xspf.cpp deleted file mode 100644 index e9a3175b3..000000000 --- a/thirdparty/liblastfm2/src/types/Xspf.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include -#include - -#include "../core/XmlQuery.h" - -#include "Xspf.h" - - -lastfm::Xspf::Xspf( const QDomElement& playlist_node, QObject* parent ) - :QObject( parent ) -{ - XmlQuery e( playlist_node ); - - int expirySeconds = e["link rel=http://www.last.fm/expiry"].text().toInt(); - QTimer::singleShot( expirySeconds * 1000, this, SLOT(onExpired())); - - m_title = e["title"].text(); - - //FIXME should we use UnicornUtils::urlDecode()? - //The title is url encoded, has + instead of space characters - //and has a + at the begining. So it needs cleaning up: - m_title.replace( '+', ' ' ); - m_title = QUrl::fromPercentEncoding( m_title.toAscii()); - m_title = m_title.trimmed(); - - foreach (XmlQuery e, e["trackList"].children( "track" )) - { - MutableTrack t; - t.setUrl( e["location"].text() ); - t.setExtra( "trackauth", e["extension"]["trackauth"].text() ); - t.setTitle( e["title"].text() ); - t.setArtist( e["creator"].text() ); - t.setAlbum( e["album"].text() ); - t.setDuration( e["duration"].text().toInt() / 1000 ); - t.setLoved( e["extension"]["loved"].text() == "1" ); - t.setSource( Track::LastFmRadio ); - - QList contexts; - QDomNodeList contextsNodeList = QDomElement(e["extension"]["context"]).childNodes(); - - for ( int i = 0 ; i < contextsNodeList.count() ; ++i ) - contexts.append( contextsNodeList.item(i).toElement().text() ); - - if ( contexts.count() > 0 ) - t.setContext( TrackContext( contextsNodeList.item(0).toElement().tagName(), contexts ) ); - - m_tracks << t; // outside try block since location is enough basically - } -} - -void -lastfm::Xspf::onExpired() -{ - emit expired(); -} diff --git a/thirdparty/liblastfm2/src/types/Xspf.h b/thirdparty/liblastfm2/src/types/Xspf.h deleted file mode 100644 index 66046b931..000000000 --- a/thirdparty/liblastfm2/src/types/Xspf.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_XSPF_H -#define LASTFM_XSPF_H - -#include -#include - -namespace lastfm -{ - class LASTFM_DLLEXPORT Xspf : public QObject - { - Q_OBJECT - public: - /** pass in the playlist node! */ - Xspf( const class QDomElement& playlist_node, QObject* parent ); - - QString title() const{ return m_title; } - - bool isEmpty() const { return m_tracks.isEmpty(); } - Track takeFirst() { return m_tracks.takeFirst(); } - - signals: - void expired(); - - private slots: - void onExpired(); - - private: - QList m_tracks; - QString m_title; - }; -} - -#endif diff --git a/thirdparty/liblastfm2/src/types/mbid_mp3.c b/thirdparty/liblastfm2/src/types/mbid_mp3.c deleted file mode 100644 index ab494a32f..000000000 --- a/thirdparty/liblastfm2/src/types/mbid_mp3.c +++ /dev/null @@ -1,181 +0,0 @@ -/* -* LICENSE -* -* Copyright (c) 2006, David Nicolson -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of the author nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT UNLESS REQUIRED BY -* LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER OR CONTRIBUTOR -* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef __MBID_MP3_H -#define __MBID_MP3_H - -#define MBID_BUFFER_SIZE 37 - -// ----------------------------------------------------------------------------- - -void mfile(size_t length, char ret[], FILE *fp, int *s) { - size_t bytes = fread(ret,1,length,fp); - - if (bytes != length) { - *s = 0; - } -} - -// ----------------------------------------------------------------------------- - -int to_synch_safe(char bytes[]) { - return ((int)bytes[0] << 21) + ((int)bytes[1] << 14) + ((int)bytes[2] << 7) + (int)bytes[3]; -} - -int to_integer(char bytes[]) { - size_t size = 0; - uint i; - for (i=0; i < sizeof(bytes); i++) { - size = size * 256 + ((int)bytes[i] & 0x000000FF); - } - return static_cast(size); -} - -// ----------------------------------------------------------------------------- - -int getMP3_MBID(const char *path, char mbid[MBID_BUFFER_SIZE]) -{ - FILE *fp; - static int s = 1; - char head[3]; - char version[2]; - char flag[1]; - char size[4]; - char size_extended[4]; - int tag_size = 0; - int extended_size = 0; - char frame[4]; - char frame_header[4]; - int frame_size; - int version_major, version_minor; - - if (path == NULL) { - //debug("Received null path\n"); - return -1; - } - - fp = fopen(path,"rb"); - if (fp == NULL) { - //debug("Failed to open music file: %s\n",path); - return -1; - } - - while (s) { - mfile(3,head,fp,&s); - if (!strncmp(head,"ID3",3) == 0) { - //debug("No ID3v2 tag found: %s\n",path); - break; - } - - mfile(2,version,fp,&s); - version_major = (int)version[0]; - version_minor = (int)version[1]; - if (version_major == 2) { - //debug("ID3v2.2.0 does not support MBIDs: %s\n",path); - break; - } - if (version_major != 3 && version_major != 4) { - //debug("Unsupported ID3 version: v2.%d.%d\n",version_major,version_minor); - break; - } - - mfile(1,flag,fp,&s); - if ((unsigned int)flag[0] & 0x00000040) { - //debug("Extended header found\n"); - if (version[0] == 4) { - mfile(4,size_extended,fp,&s); - extended_size = to_synch_safe(size_extended); - } else { - mfile(4,size_extended,fp,&s); - extended_size = to_integer(size_extended); - } - //debug("Extended header size: %d\n",extended_size); - fseek(fp,extended_size,SEEK_CUR); - } - - mfile(4,size,fp,&s); - tag_size = to_synch_safe(size); - //debug("Tag size: %d\n",tag_size); - - while (s) { - if (ftell(fp) > tag_size || ftell(fp) > 1048576) { - break; - } - - mfile(4,frame,fp,&s); - if (frame[0] == 0x00) { - break; - } - if (version_major == 4) { - mfile(4,frame_header,fp,&s); - frame_size = to_synch_safe(frame_header); - } else { - mfile(4,frame_header,fp,&s); - frame_size = to_integer(frame_header); - } - - fseek(fp,2,SEEK_CUR); - //debug("Reading %d bytes from frame %s\n",frame_size,frame); - - if (strncmp(frame,"UFID",4) == 0) { - //char frame_data[frame_size]; - char frame_data[59]; - mfile(59,frame_data,fp,&s); - if (frame_size >= 59 && strncmp(frame_data,"http://musicbrainz.org",22) == 0) { - char *tmbid = frame_data; - tmbid = frame_data + 23; - strncpy(mbid,tmbid,MBID_BUFFER_SIZE-1); - mbid[MBID_BUFFER_SIZE-1] = 0x00; - fclose(fp); - return 0; - } - } else { - fseek(fp,frame_size,SEEK_CUR); - } - } - break; - } - - if (fp) { - fclose(fp); - } - //if (!s) { - // debug("Failed to read music file: %s\n",path); - //} - return -1; - -} - -#endif - -// ----------------------------------------------------------------------------- diff --git a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp b/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp deleted file mode 100644 index 0fe9b9394..000000000 --- a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "InternetConnectionMonitor.h" -#include "linux/LNetworkConnectionMonitor.h" -#include "mac/MNetworkConnectionMonitor.h" -#include "win/WNetworkConnectionMonitor.h" -#include "NetworkConnectionMonitor.h" -#include "ws.h" - -lastfm::InternetConnectionMonitor::InternetConnectionMonitor( QObject *parent ) - : QObject( parent ) - , m_up( true ) -{ - m_networkMonitor = createNetworkConnectionMonitor(); - - if ( m_networkMonitor ) - { - connect( m_networkMonitor, SIGNAL( networkUp() ), this, SLOT( onNetworkUp() ) ); - connect( m_networkMonitor, SIGNAL( networkDown() ), this, SLOT( onNetworkDown() ) ); - } - - connect( lastfm::nam(), SIGNAL( finished( QNetworkReply* ) ), this, SLOT( onFinished( QNetworkReply* ) ) ); -} - -void -lastfm::InternetConnectionMonitor::onFinished( QNetworkReply* reply ) -{ - if( reply->attribute( QNetworkRequest::SourceIsFromCacheAttribute).toBool() ) return; - - switch( reply->error() ) - { - case QNetworkReply::NoError: - if ( !m_up ) - { - m_up = true; - emit up(); - emit connectivityChanged( m_up ); - qDebug() << "Internet connection is reachable :)"; - } - break; - case QNetworkReply::HostNotFoundError: - case QNetworkReply::TimeoutError: - case QNetworkReply::ProxyConnectionRefusedError: - case QNetworkReply::ProxyConnectionClosedError: - case QNetworkReply::ProxyNotFoundError: - case QNetworkReply::ProxyTimeoutError: - case QNetworkReply::ProxyAuthenticationRequiredError: - if ( m_up ) - { - m_up = false; - emit down(); - emit connectivityChanged( m_up ); - } - break; - default: - break; - } -} - -void -lastfm::InternetConnectionMonitor::onNetworkUp() -{ -#ifdef Q_OS_MAC - // We don't need to check on mac as the - // check is done as part of the reach api - m_up = true; - emit up(); - emit connectivityChanged( m_up ); - qDebug() << "Internet connection is reachable :)"; -#else - qDebug() << "Network seems to be up again. Let's try if there's internet connection!"; - lastfm::nam()->head( QNetworkRequest( QUrl( tr( "http://www.last.fm/" ) ) ) ); -#endif -} - -void -lastfm::InternetConnectionMonitor::onNetworkDown() -{ - qDebug() << "Internet is unreachable :("; - m_up = false; - emit down(); - emit connectivityChanged( m_up ); -} - -NetworkConnectionMonitor* -lastfm::InternetConnectionMonitor::createNetworkConnectionMonitor() -{ - NetworkConnectionMonitor* ncm = 0; - -#ifdef Q_WS_X11 - ncm = new LNetworkConnectionMonitor( this ); -#elif defined(Q_WS_WIN) - ncm = new WNetworkConnectionMonitor( this ); -#elif defined(Q_WS_MAC) - ncm = new MNetworkConnectionMonitor( this ); -#endif - - return ncm; -} diff --git a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h deleted file mode 100644 index 3f770125c..000000000 --- a/thirdparty/liblastfm2/src/ws/InternetConnectionMonitor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef LASTFM_CONNECTION_MONITOR_H -#define LASTFM_CONNECTION_MONITOR_H - -#include -#include - -class NetworkConnectionMonitor; - -#ifdef Q_WS_X11 -class LNetworkConnectionMonitor; -#endif - -namespace lastfm { - -class LASTFM_DLLEXPORT InternetConnectionMonitor : public QObject -{ - Q_OBJECT - enum NMState - { - Unknown, - Asleep, - Connecting, - Connected, - Disconnected - }; - -public: - /** if internet is unavailable you will get a down() signal soon, otherwise - * you won't get a signal until the net goes down */ - InternetConnectionMonitor( QObject *parent = 0 ); - - bool isDown() const { return !m_up; } - bool isUp() const { return m_up; } - - NetworkConnectionMonitor* createNetworkConnectionMonitor(); - -signals: - /** yay! internet has returned */ - void up( const QString& connectionName = "" ); - - /** we think the internet is unavailable, but well, still try, but show - * an unhappy face in the statusbar or something */ - void down( const QString& connectionName = "" ); - - /** emitted after the above */ - void connectivityChanged( bool ); - -private slots: - void onFinished( QNetworkReply* reply ); - void onNetworkUp(); - void onNetworkDown(); - -private: - bool m_up; - NetworkConnectionMonitor* m_networkMonitor; -}; - -} //namespace lastfm - -#endif diff --git a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp b/thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp deleted file mode 100644 index 16ac5e78e..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "NetworkAccessManager.h" -#include "InternetConnectionMonitor.h" -#include -#include -#include -#include -#ifdef WIN32 -#include "win/IeSettings.h" -#include "win/Pac.h" -#endif -#ifdef __APPLE__ -#include "mac/ProxyDict.h" -#endif - - -static struct NetworkAccessManagerInit -{ - // We do this upfront because then our Firehose QTcpSocket will have a proxy - // set by default. As well as any plain QNetworkAcessManager stuff, and the - // scrobbler - // In theory we should do this every request in case the configuration - // changes but that is fairly unlikely use case, init? Maybe we should - // anyway.. - - NetworkAccessManagerInit() - { - #ifdef WIN32 - IeSettings s; - // if it's autodetect, we determine the proxy everytime in proxy() - // we don't really want to do a PAC lookup here, as it times out - // at two seconds, so that hangs startup - if (!s.fAutoDetect && s.lpszProxy) - { - QUrl url( QString::fromUtf16((const unsigned short*)s.lpszProxy) ); - QNetworkProxy proxy( QNetworkProxy::HttpProxy ); - proxy.setHostName( url.host() ); - proxy.setPort( url.port() ); - QNetworkProxy::setApplicationProxy( proxy ); - } - #endif - #ifdef __APPLE__ - ProxyDict dict; - if (dict.isProxyEnabled()) - { - QNetworkProxy proxy( QNetworkProxy::HttpProxy ); - proxy.setHostName( dict.host ); - proxy.setPort( dict.port ); - - QNetworkProxy::setApplicationProxy( proxy ); - } - #endif - } -} init; - - -namespace lastfm -{ - LASTFM_DLLEXPORT QByteArray UserAgent; -} - - -lastfm::NetworkAccessManager::NetworkAccessManager( QObject* parent ) - : QNetworkAccessManager( parent ) - #ifdef WIN32 - , m_pac( 0 ) - , m_monitor( 0 ) - #endif -{ - // can't be done in above init, as applicationName() won't be set - if (lastfm::UserAgent.isEmpty()) - { - QByteArray name = QCoreApplication::applicationName().toUtf8(); - QByteArray version = QCoreApplication::applicationVersion().toUtf8(); - if (version.size()) version.prepend( ' ' ); - lastfm::UserAgent = name + version + " (" + lastfm::platform() + ")"; - } -} - - -lastfm::NetworkAccessManager::~NetworkAccessManager() -{ -#ifdef WIN32 - delete m_pac; -#endif -} - - -QNetworkProxy -lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request ) -{ - Q_UNUSED( request ); - -#ifdef WIN32 - IeSettings s; - if (s.fAutoDetect) - { - if (!m_pac) { - m_pac = new Pac; - if ( !m_monitor ) - { - m_monitor = new InternetConnectionMonitor( this ); - connect( m_monitor, SIGNAL( connectivityChanged( bool ) ), SLOT( onConnectivityChanged( bool ) ) ); - } - } - return m_pac->resolve( request, s.lpszAutoConfigUrl ); - } -#endif - - return QNetworkProxy::applicationProxy(); -} - - -QNetworkReply* -lastfm::NetworkAccessManager::createRequest( Operation op, const QNetworkRequest& request_, QIODevice* outgoingData ) -{ - QNetworkRequest request = request_; - - request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); - request.setRawHeader( "User-Agent", lastfm::UserAgent ); - -#ifdef WIN32 - // PAC proxies can vary by domain, so we have to check everytime :( - QNetworkProxy proxy = this->proxy( request ); - if (proxy.type() != QNetworkProxy::NoProxy) - QNetworkAccessManager::setProxy( proxy ); -#endif - - return QNetworkAccessManager::createRequest( op, request, outgoingData ); -} - - -void -lastfm::NetworkAccessManager::onConnectivityChanged( bool up ) -{ - Q_UNUSED( up ); - -#ifdef WIN32 - if (up && m_pac) m_pac->resetFailedState(); -#endif -} diff --git a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.h b/thirdparty/liblastfm2/src/ws/NetworkAccessManager.h deleted file mode 100644 index a3022ce25..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkAccessManager.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_WS_ACCESS_MANAGER_H -#define LASTFM_WS_ACCESS_MANAGER_H - -#include -#include -#include -#include - - -namespace lastfm { - -/** Sets useragent and proxy. Auto detecting the proxy where possible. */ -class LASTFM_DLLEXPORT NetworkAccessManager : public QNetworkAccessManager -{ - Q_OBJECT - -#ifdef Q_WS_WIN - class Pac *m_pac; - class InternetConnectionMonitor* m_monitor; -#endif - -public: - NetworkAccessManager( QObject *parent = 0 ); - ~NetworkAccessManager(); - - /** PAC allows different proxy configurations depending on the request - * URL and even UserAgent! Thus we allow you to pass that in, we - * automatically configure the proxy for every request through - * WsAccessManager */ - QNetworkProxy proxy( const QNetworkRequest& = QNetworkRequest() ); - -protected: - virtual QNetworkReply* createRequest( Operation, const QNetworkRequest&, QIODevice* outgoingdata = 0 ); - -private slots: - void onConnectivityChanged( bool ); - -private: - /** this function calls QNetworkAccessManager::setProxy, and thus - * configures the proxy correctly for the next request created by - * createRequest. This is necessary due */ - void applyProxy( const QNetworkRequest& ); -}; - -} //namespace lastfm - -#endif diff --git a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp b/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp deleted file mode 100644 index b4a62732b..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "NetworkConnectionMonitor.h" - -NetworkConnectionMonitor::NetworkConnectionMonitor( QObject* /*parent*/ ) - : m_connected( true ) -{ -} - -NetworkConnectionMonitor::~NetworkConnectionMonitor() -{ -} - -bool -NetworkConnectionMonitor::isConnected() const -{ - return m_connected; -} - -void -NetworkConnectionMonitor::setConnected( bool connected ) -{ - if ( m_connected != connected ) - { - m_connected = connected; - - if ( connected ) - emit networkUp(); - else - emit networkDown(); - } -} - diff --git a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h deleted file mode 100644 index a21cf73e3..000000000 --- a/thirdparty/liblastfm2/src/ws/NetworkConnectionMonitor.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Jono Cole, Michael Coffey, and William Viana - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef NETWORK_CONNECTION_MONITOR_H -#define NETWORK_CONNECTION_MONITOR_H - -#include -#include - -class LASTFM_DLLEXPORT NetworkConnectionMonitor : public QObject -{ - Q_OBJECT -public: - NetworkConnectionMonitor( QObject *parent = 0 ); - ~NetworkConnectionMonitor(); - bool isConnected() const; - -signals: - void networkUp(); - void networkDown(); - -protected: - void setConnected( bool connected ); - -private: - bool m_connected; -}; - -#endif // NETWORK_CONNECTION_MONITOR_H diff --git a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h deleted file mode 100644 index 9f7895bed..000000000 --- a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - - -#ifndef LNETWORK_CONNECTION_MONITOR_H -#define LNETWORK_CONNECTION_MONITOR_H - -#include "../NetworkConnectionMonitor.h" -#include -#include - -class QDBusConnection; -class QDBusInterface; - -class LNetworkConnectionMonitor : public NetworkConnectionMonitor -{ - Q_OBJECT - - enum NMState - { - Unknown=1, - Asleep, - Connected, - Disconnected - }; - -public: - LNetworkConnectionMonitor( QObject* parent = 0 ); - ~LNetworkConnectionMonitor(); -private slots: - void onStateChange( uint newState ); -private: - QDBusInterface* m_nmInterface; -}; - -#endif // LNETWORK_CONNECTION_MONITOR_H - diff --git a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp b/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp deleted file mode 100644 index d8dea9dd6..000000000 --- a/thirdparty/liblastfm2/src/ws/linux/LNetworkConnectionMonitor_linux.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - - -#include "LNetworkConnectionMonitor.h" - -#include -#include -#include - -LNetworkConnectionMonitor::LNetworkConnectionMonitor( QObject* parent ) : - NetworkConnectionMonitor( parent ) -{ - m_nmInterface = new QDBusInterface( QString( "org.freedesktop.NetworkManager" ), - QString( "/org/freedesktop/NetworkManager" ), - QString( "org.freedesktop.NetworkManager" ), - QDBusConnection::systemBus(), - this ); - - //get current connection state - QDBusInterface* dbusInterface = new QDBusInterface( QString( "org.freedesktop.NetworkManager" ), - QString( "/org/freedesktop/NetworkManager" ), - QString( "org.freedesktop.DBus.Properties" ), - QDBusConnection::systemBus(), - this ); - - QDBusReply reply = dbusInterface->call( "Get", "org.freedesktop.NetworkManager", "state" ); - if ( reply.isValid() ) - { - if ( reply.value() == Connected ) - { - setConnected( true ); - } - else if ( reply.value() == Disconnected ) - { - setConnected( false ); - } - } - else - { - qDebug() << "Error: " << reply.error(); - } - delete dbusInterface; - - //connect network manager signals - connect( m_nmInterface, SIGNAL( StateChange( uint ) ), this, SLOT( onStateChange( uint ) ) ); - -} - -LNetworkConnectionMonitor::~LNetworkConnectionMonitor() -{ - delete m_nmInterface; -} - - -void -LNetworkConnectionMonitor::onStateChange( uint newState ) -{ - qDebug() << "Networkmanager state change!"; - - if ( newState == Disconnected ) - { - setConnected( false ); - } - else if ( newState == Connected ) - { - setConnected( true ); - } -} diff --git a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h deleted file mode 100644 index 96aca0767..000000000 --- a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Jono Cole and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef MNETWORK_CONNECTION_MONITOR_H -#define MNETWORK_CONNECTION_MONITOR_H - -#include "../NetworkConnectionMonitor.h" -#include -#include - -#ifdef Q_WS_MAC -#include //TODO remove -#include -#endif - -class __SCNetworkReachability; - -class MNetworkConnectionMonitor : public NetworkConnectionMonitor -{ - Q_OBJECT -public: - MNetworkConnectionMonitor( QObject* parent = 0 ); - ~MNetworkConnectionMonitor(); -private slots: - -private: -#ifdef Q_WS_MAC - static void callback( SCNetworkReachabilityRef target, - SCNetworkConnectionFlags flags, - void *info ); -#endif -}; - -#endif // MNETWORK_CONNECTION_MONITOR_H - diff --git a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp b/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp deleted file mode 100644 index fd966a4ec..000000000 --- a/thirdparty/liblastfm2/src/ws/mac/MNetworkConnectionMonitor_mac.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Jono Cole and Michael Coffey - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "MNetworkConnectionMonitor.h" - -#include -#include - -#include "../ws.h" - -MNetworkConnectionMonitor* context = 0; - -MNetworkConnectionMonitor::MNetworkConnectionMonitor( QObject* parent ) : - NetworkConnectionMonitor( parent ) -{ - context = this; - - SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName( NULL, LASTFM_WS_HOSTNAME ); - SCNetworkReachabilityScheduleWithRunLoop( ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - SCNetworkReachabilitySetCallback( ref, callback, NULL ); - CFRelease( ref ); -} - -MNetworkConnectionMonitor::~MNetworkConnectionMonitor() -{ -} - - -void -MNetworkConnectionMonitor::callback( SCNetworkReachabilityRef target, - SCNetworkConnectionFlags flags, - void * ) -{ - static bool up = true; - - // I couldn't find any diffinitive usage examples for these flags - // so I had to guess, since I can't test, eg. dial up :( - - bool b; - if (flags & kSCNetworkFlagsConnectionRequired) - b = false; - else - b = flags & (kSCNetworkFlagsReachable | kSCNetworkFlagsTransientConnection | kSCNetworkFlagsConnectionAutomatic); - - // basically, avoids telling everyone that we're up already on startup - if (up == b) - return; - - up = b; - - context->setConnected(b); -} - diff --git a/thirdparty/liblastfm2/src/ws/mac/ProxyDict.h b/thirdparty/liblastfm2/src/ws/mac/ProxyDict.h deleted file mode 100644 index 2d873f88a..000000000 --- a/thirdparty/liblastfm2/src/ws/mac/ProxyDict.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include - - -struct ProxyDict -{ - ProxyDict(); - - int port; - QString host; - - bool isProxyEnabled() const { return port > 0 && host.size(); } -}; - - -inline ProxyDict::ProxyDict() : port( 0 ) -{ - // Get the dictionary. - CFDictionaryRef proxyDict = SCDynamicStoreCopyProxies( NULL ); - bool result = (proxyDict != NULL); - - // Get the enable flag. This isn't a CFBoolean, but a CFNumber. - CFNumberRef enableNum; - int enable; - if (result) { - enableNum = (CFNumberRef) CFDictionaryGetValue( proxyDict, kSCPropNetProxiesHTTPEnable ); - result = (enableNum != NULL) && (CFGetTypeID(enableNum) == CFNumberGetTypeID()); - } - if (result) - result = CFNumberGetValue( enableNum, kCFNumberIntType, &enable ) && (enable != 0); - - // Get the proxy host. DNS names must be in ASCII. If you - // put a non-ASCII character in the "Secure Web Proxy" - // field in the Network preferences panel, the CFStringGetCString - // function will fail and this function will return false. - CFStringRef hostStr; - if (result) { - hostStr = (CFStringRef) CFDictionaryGetValue( proxyDict, kSCPropNetProxiesHTTPProxy ); - result = (hostStr != NULL) && (CFGetTypeID(hostStr) == CFStringGetTypeID()); - } - if (result) - host = lastfm::CFStringToQString( hostStr ); - - // get the proxy port - CFNumberRef portNum; - - if (result) { - portNum = (CFNumberRef) CFDictionaryGetValue( proxyDict, kSCPropNetProxiesHTTPPort ); - result = (portNum != NULL) && (CFGetTypeID(portNum) == CFNumberGetTypeID()); - } - if (result) - result = CFNumberGetValue( portNum, kCFNumberIntType, &port ); - - // clean up. - if (proxyDict != NULL) - CFRelease( proxyDict ); -} diff --git a/thirdparty/liblastfm2/src/ws/win/ComSetup.h b/thirdparty/liblastfm2/src/ws/win/ComSetup.h deleted file mode 100644 index ce8685428..000000000 --- a/thirdparty/liblastfm2/src/ws/win/ComSetup.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef _WIN32_WINNT -// bring in CoInitializeSecurity from objbase.h -#define _WIN32_WINNT 0x0400 -#endif - -#include -#include "winable.h" -//#include -//#include - - -/** @brief WsConnectionMonitor needs Com to work as early as possible so we do this - * @author - */ -class ComSetup -{ -public: - ComSetup() - { - HRESULT hr = CoInitialize(0); - m_bComInitialised = SUCCEEDED(hr); - //_ASSERT(m_bComInitialised); - if (m_bComInitialised) { - setupSecurity(); - } - } - - void setupSecurity() - { - //CSecurityDescriptor sd; - //sd.InitializeFromThreadToken(); - //HRESULT hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); - //_ASSERT(SUCCEEDED(hr)); - } - - ~ComSetup() - { - if (m_bComInitialised) { - CoUninitialize(); - } - } - -private: - bool m_bComInitialised; -}; diff --git a/thirdparty/liblastfm2/src/ws/win/IeSettings.h b/thirdparty/liblastfm2/src/ws/win/IeSettings.h deleted file mode 100644 index 414ce6507..000000000 --- a/thirdparty/liblastfm2/src/ws/win/IeSettings.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include -#include - - -/** @brief memory managing wrapper for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG - * @author - */ -struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG -{ -/* IeSettings() - { - if (!WinHttpGetIEProxyConfigForCurrentUser(this)) { - fAutoDetect = FALSE; - lpszAutoConfigUrl = lpszProxy = lpszProxyBypass = 0; - } - } - - ~IeSettings() - { - if (lpszAutoConfigUrl) GlobalFree(lpszAutoConfigUrl); - if (lpszProxy) GlobalFree(lpszProxy); - if (lpszProxyBypass) GlobalFree(lpszProxyBypass); - }*/ -}; diff --git a/thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp b/thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp deleted file mode 100644 index 64eda9b36..000000000 --- a/thirdparty/liblastfm2/src/ws/win/NdisEvents.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "NdisEvents.h" -#include "WmiSink.h" - -// see http://msdn.microsoft.com/en-us/magazine/cc301850.aspx for -// more about Ndis and wmi and getting these events - -// Link to wbemuuid.lib to resolve IWbemObjectSink and IWbemClassObject -// interface definitions. - -NdisEvents::NdisEvents() - : m_pSink(0) -{} - -NdisEvents::~NdisEvents() -{ -// if (m_pSink) -// m_pSink->disconnect(); -// if (m_pServices && m_pSink) -// m_pServices->CancelAsyncCall(m_pSink); - // and reference counting will take care of the WmiSink object -} - -HRESULT -NdisEvents::registerForNdisEvents() -{ - HRESULT hr = 0; // m_pLocator.CoCreateInstance(CLSID_WbemLocator); - if (FAILED(hr)) - return hr; - - // Connect to the root\wmi namespace with the current user. - hr = 0; /*m_pLocator->ConnectServer(CComBSTR("ROOT\\WMI"), // strNetworkResource - NULL, // strUser - NULL, // strPassword - NULL, // strLocale - 0, // lSecurityFlags - CComBSTR(""), // strAuthority - NULL, // pCtx - &m_pServices - );*/ - if (FAILED(hr)) - return hr; - -// m_pSink = new WmiSink(this); - - ////////////////////////// - - // other notifications we're not interested in right now include... - // MSNdis_NotifyAdapterArrival \DEVICE\ - // MSNdis_NotifyAdapterRemoval - // MSNdis_StatusLinkSpeedChange - // MSNdis_NotifyVcArrival - // MSNdis_NotifyVcRemoval - // MSNdis_StatusResetStart - // MSNdis_StatusResetEnd - // MSNdis_StatusProtocolBind - // MSNdis_StatusProtocolUnbind - // MSNdis_StatusMediaSpecificIndication - -/* CComBSTR wql("WQL"); - CComBSTR query("SELECT * FROM MSNdis_StatusMediaDisconnect"); - hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink); - - query = "SELECT * FROM MSNdis_StatusMediaConnect"; - hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);*/ - - return S_OK; -} - diff --git a/thirdparty/liblastfm2/src/ws/win/NdisEvents.h b/thirdparty/liblastfm2/src/ws/win/NdisEvents.h deleted file mode 100644 index 9d3fa0735..000000000 --- a/thirdparty/liblastfm2/src/ws/win/NdisEvents.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef NDIS_EVENTS_H -#define NDIS_EVENTS_H - -#include -//#include -//#include - -class NdisEvents -{ -public: - NdisEvents(); - ~NdisEvents(); - HRESULT registerForNdisEvents(); - - virtual void onConnectionUp(BSTR name) = 0; - virtual void onConnectionDown(BSTR name) = 0; - -private: -// CComPtr m_pLocator; -// CComPtr m_pServices; - class WmiSink *m_pSink; -}; - -#endif - diff --git a/thirdparty/liblastfm2/src/ws/win/Pac.cpp b/thirdparty/liblastfm2/src/ws/win/Pac.cpp deleted file mode 100644 index 9a73468a9..000000000 --- a/thirdparty/liblastfm2/src/ws/win/Pac.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "Pac.h" -#include -#include -#include -#include -//#include -//#include - - -static bool -parsePacServer(const QString &s, QNetworkProxy &p) -{ - // remove optional leading "scheme=" portion - int start = s.indexOf('='); - QUrl url(s.mid(start+1), QUrl::TolerantMode); - - if (url.isValid()) - { - p.setHostName(url.host()); - p.setPort(url.port()); - return true; - } - return false; -} - - -static QList -parsePacResult(const QString &pacResult) -{ - // msdn says: "The proxy server list contains one or more of the - // following strings separated by semicolons or whitespace." - // ([=]["://"][":"]) - - QList result; - QStringList proxies = pacResult.split(QRegExp("[\\s;]"), QString::SkipEmptyParts); - foreach(const QString &s, proxies) - { - QNetworkProxy proxy( QNetworkProxy::HttpProxy ); - if (parsePacServer(s, proxy)) - { - result << proxy; - } - } - return result; -} - - -//////////////// - - -lastfm::Pac::Pac() - : m_bFailed( false ) - , m_hSession( 0 ) -{} - -lastfm::Pac::~Pac() -{ -/* if (m_hSession) - WinHttpCloseHandle(m_hSession);*/ -} - -QNetworkProxy -lastfm::Pac::resolve(const QNetworkRequest &request, const wchar_t* pacUrl) -{ - QNetworkProxy out; - if (m_bFailed) return out; - - if (!m_hSession) - { - QByteArray user_agent = request.rawHeader("user-agent"); - //m_hSession = WinHttpOpen(CA2W(user_agent), WINHTTP_ACCESS_TYPE_NO_PROXY, 0, 0, WINHTTP_FLAG_ASYNC); - } - if (m_hSession) - { - WINHTTP_PROXY_INFO info; - WINHTTP_AUTOPROXY_OPTIONS opts; - memset(&opts, 0, sizeof(opts)); - if (pacUrl) - { - // opts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; - // opts.lpszAutoConfigUrl = pacUrl; - } - else - { - // opts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; - // opts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; - } - opts.fAutoLogonIfChallenged = TRUE; - -/* if (WinHttpGetProxyForUrl(m_hSession, (const WCHAR*)request.url().toString().utf16(), &opts, &info)) { - if (info.lpszProxy) - { - QList proxies = parsePacResult(QString::fromUtf16((const ushort*)info.lpszProxy)); - if (!proxies.empty()) - { - out = proxies.at(0); - } - GlobalFree((void*)info.lpszProxy); - } - if (info.lpszProxyBypass) - { - GlobalFree((void*)info.lpszProxyBypass); - } - } else { - m_bFailed = true; - }*/ - } - - return out; -} diff --git a/thirdparty/liblastfm2/src/ws/win/Pac.h b/thirdparty/liblastfm2/src/ws/win/Pac.h deleted file mode 100644 index 075d128f6..000000000 --- a/thirdparty/liblastfm2/src/ws/win/Pac.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef WS_AUTOPROXY_H -#define WS_AUTOPROXY_H - -#include -#include -#include -class QNetworkRequest; - -namespace lastfm -{ - /** @brief simple wrapper to do per url automatic proxy detection - * @author - */ - class Pac - { - HINTERNET m_hSession; - bool m_bFailed; - - public: - Pac(); - ~Pac(); - - QNetworkProxy resolve( const QNetworkRequest& url, const wchar_t* pacUrl ); - - void resetFailedState() { m_bFailed = false; } - - private: - Pac( const Pac& ); //undefined - Pac operator=( const Pac& ); //undefined - }; -} - -#endif \ No newline at end of file diff --git a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h b/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h deleted file mode 100755 index 26fb58cdd..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Jono Cole, Michael Coffey, and William Viana - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#ifndef WNETWORK_CONNECTION_MONITOR_H -#define WNETWORK_CONNECTION_MONITOR_H - -#include "../NetworkConnectionMonitor.h" -#include -#include - -namespace lastfm { class NdisEventsProxy; } - -class WNetworkConnectionMonitor : public NetworkConnectionMonitor -{ - Q_OBJECT -public: - friend class lastfm::NdisEventsProxy; - - WNetworkConnectionMonitor( QObject* parent = 0 ); - ~WNetworkConnectionMonitor(); - -private: - lastfm::NdisEventsProxy* m_ndisEventsProxy; -}; - -#endif // WNETWORK_CONNECTION_MONITOR_H - diff --git a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp b/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp deleted file mode 100755 index 09fd97cc5..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WNetworkConnectionMonitor_win.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright 2010 Last.fm Ltd. - - Primarily authored by Jono Cole, Michael Coffey, and William Viana - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ - -#include "WNetworkConnectionMonitor.h" - -// WsAccessManager needs special init (on Windows), and it needs to be done -// early, so be careful about moving this -#include "../win/ComSetup.h" //must be first header or compile fail results! -#include "../win/NdisEvents.h" -static ComSetup com_setup; - -namespace lastfm { - -// bounce NdisEvents signals through here so we don't have to expose the -// NdisEvents interface in InternetConnectionMonitor :) -class NdisEventsProxy : public NdisEvents -{ -public: - NdisEventsProxy(WNetworkConnectionMonitor* icm) - :m_icm(icm) - { - } - - // WmiSink callbacks: - void onConnectionUp( BSTR /*name*/ ) - { - m_icm->setConnected( true ); - } - - void onConnectionDown( BSTR /*name*/ ) - { - m_icm->setConnected( false ); - } - - WNetworkConnectionMonitor* m_icm; -}; - -} - -WNetworkConnectionMonitor::WNetworkConnectionMonitor( QObject* parent ) : - NetworkConnectionMonitor( parent ) -{ - m_ndisEventsProxy = new lastfm::NdisEventsProxy( this ); - m_ndisEventsProxy->registerForNdisEvents(); -} - -WNetworkConnectionMonitor::~WNetworkConnectionMonitor() -{ - delete m_ndisEventsProxy; -} diff --git a/thirdparty/liblastfm2/src/ws/win/WmiSink.cpp b/thirdparty/liblastfm2/src/ws/win/WmiSink.cpp deleted file mode 100644 index 3d564266c..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WmiSink.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "WmiSink.h" -#include "NdisEvents.h" - - -WmiSink::WmiSink(NdisEvents *callback) - : m_cRef(1) - , m_callback(callback) -{} - -WmiSink::~WmiSink() -{} - -void -WmiSink::disconnect() -{ - m_callback = 0; -} - -STDMETHODIMP -WmiSink::QueryInterface(REFIID riid, LPVOID * ppv) -{ - *ppv = 0; - - if (IID_IUnknown==riid || IID_IWbemObjectSink == riid) - { - *ppv = (IWbemObjectSink *) this; - AddRef(); - return NOERROR; - } - - return E_NOINTERFACE; -} - - -ULONG -WmiSink::AddRef() -{ - return ++m_cRef; -} - -ULONG -WmiSink::Release() -{ - if (0 != --m_cRef) - return m_cRef; - - delete this; - return 0; -} - -// This method receives notification objects. -HRESULT -WmiSink::Indicate(long lObjectCount, IWbemClassObject** ppObjArray) -{ - // For each object in the array, extract the object and display the - // information in the object. - for (long i=0; iGet(L"InstanceName", 0, &vt, NULL, NULL); - ppObjArray[i]->Get(L"__Class", 0, &vtClass, NULL, NULL); - - if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusMediaDisconnect")) - { - if (m_callback) m_callback->onConnectionDown(vt.bstrVal); - } - else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusMediaConnect")) - { - if (m_callback) m_callback->onConnectionUp(vt.bstrVal); - } - // notifications we aren't interested in right now: - // - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyAdapterRemoval")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get (L"DeviceName", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(": ") + (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has been removed"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyAdapterArrival")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get(L"DeviceName", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(": ") + (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has been added"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusResetStart")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has begun a reset"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusResetEnd")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal + (_bstr_t) _T(" has finished a reset"); - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyVcArrival")) - //{ - // bstrLog = (_bstr_t) _T("VC arrival: ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_NotifyVcRemoval")) - //{ - // bstrLog = (_bstr_t) _T("VC removal: ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusMediaSpecificIndication")) - //{ - // ATLTRACE (_T("Media specific indication: %s\n"), (TCHAR *) (_bstr_t) vt.bstrVal); - // VariantClear (&vt); - // ppObjArray[i]->Get (L"NdisStatusMediaSpecificIndication", 0, &vt, NULL, NULL); - // LONG lLowerBound, lUpperBound, j; - // UCHAR ch; - // SafeArrayGetLBound (V_ARRAY (&vt), 1, &lLowerBound); - // SafeArrayGetUBound (V_ARRAY (&vt), 1, &lUpperBound); - // ATLTRACE (" "); - // for (j = lLowerBound; j<= lUpperBound; j++ ) - // { - // SafeArrayGetElement (V_ARRAY (&vt), &j, &ch); - // ATLTRACE (_T("%4i"), ch); - - // if (((j - lLowerBound) % 8 == 7) && (j <= lUpperBound)) - // ATLTRACE (_T("\n")); - // } - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusProtocolBind")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get (L"Transport", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(" is now bound to ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusProtocolBind")) - //{ - // bstrLog = (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get(L"Transport", 0, &vt, NULL, NULL); - // bstrLog += (_bstr_t) _T(" was unbound from ") + (_bstr_t) vt.bstrVal; - // displayDlg.LogEvent (bstrLog); - //} - //else if (!wcscmp (vtClass.bstrVal, L"MSNdis_StatusLinkSpeedChange")) - //{ - // IWbemClassObject* pWMIObj=NULL; - // bstrLog = (_bstr_t) _T("Link speed change ") + (_bstr_t) vt.bstrVal; - // VariantClear (&vt); - // ppObjArray[i]->Get (L"NdisStatusLinkSpeedChange", 0, &vt, NULL, NULL); - // if SUCCEEDED (vt.punkVal->QueryInterface (IID_IWbemClassObject, (void**)&pWMIObj)) - // { - // TCHAR szNum[50]; - // pWMIObj->Get (L"Inbound", 0, &vt2, NULL, NULL); - // _stprintf (szNum, _T(" Inbound = %u "), vt2.lVal); - // bstrLog += (_bstr_t) szNum; - // VariantClear (&vt2); - // pWMIObj->Get (L"Outbound", 0, &vt2, NULL, NULL); - // _stprintf (szNum, _T(" Outbound = %u "), vt2.lVal); - // bstrLog += (_bstr_t) szNum; - // VariantClear (&vt2); - // pWMIObj->Release (); - // pWMIObj = NULL; - // } - // displayDlg.LogEvent (bstrLog); - //} - - VariantClear (&vtClass); - VariantClear (&vt); - } - return WBEM_NO_ERROR; -} - - -// Misc. status codes sent by sink. -HRESULT -WmiSink::SetStatus(long lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam) -{ - lFlags; - hResult; - strParam; - pObjParam; - return WBEM_NO_ERROR; -} diff --git a/thirdparty/liblastfm2/src/ws/win/WmiSink.h b/thirdparty/liblastfm2/src/ws/win/WmiSink.h deleted file mode 100644 index 74319eb6a..000000000 --- a/thirdparty/liblastfm2/src/ws/win/WmiSink.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef WMISINK_WIN_H -#define WMISINK_WIN_H - -#include "wbemcli.h" - -// Sink object for WMI NDIS notifications -class WmiSink : public IWbemObjectSink -{ - UINT m_cRef; - -public: - WmiSink(class NdisEvents *callback); - ~WmiSink(); - - // IUnknown members - STDMETHODIMP QueryInterface(REFIID, LPVOID *); - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP_(ULONG) Release(void); - - // IWbemObjectSink - STDMETHODIMP Indicate(long, IWbemClassObject**); - STDMETHODIMP SetStatus(long, HRESULT, BSTR, IWbemClassObject *); - - void disconnect(); - -private: - class NdisEvents *m_callback; -}; - -#endif \ No newline at end of file diff --git a/thirdparty/liblastfm2/src/ws/ws.cpp b/thirdparty/liblastfm2/src/ws/ws.cpp deleted file mode 100644 index b2ad56860..000000000 --- a/thirdparty/liblastfm2/src/ws/ws.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#include "ws.h" -#include "../core/misc.h" -#include "NetworkAccessManager.h" -#include -#include -#include -#include -#include -#include -#include -#include - -static QMap< QThread*, QNetworkAccessManager* > threadNamHash; -static QSet< QThread* > ourNamSet; -static QMutex namAccessMutex; - -QString -lastfm::ws::host() -{ - QStringList const args = QCoreApplication::arguments(); - if (args.contains( "--debug")) - return "ws.staging.audioscrobbler.com"; - - int const n = args.indexOf( "--host" ); - if (n != -1 && args.count() > n+1) - return args[n+1]; - - return LASTFM_WS_HOSTNAME; -} - -static QUrl baseUrl() -{ - QUrl url; - url.setScheme( "http" ); - url.setHost( lastfm::ws::host() ); - url.setEncodedPath( "/2.0/" ); - return url; -} - -static QString iso639() -{ - return QLocale().name().left( 2 ).toLower(); -} - -void autograph( QMap& params ) -{ - params["api_key"] = lastfm::ws::ApiKey; - params["lang"] = iso639(); -} - -static void sign( QMap& params, bool sk = true ) -{ - autograph( params ); - // it's allowed for sk to be null if we this is an auth call for instance - if (sk && lastfm::ws::SessionKey.size()) - params["sk"] = lastfm::ws::SessionKey; - - QString s; - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - s += i.key() + i.value(); - } - s += lastfm::ws::SharedSecret; - - params["api_sig"] = lastfm::md5( s.toUtf8() ); -} - - -QUrl -lastfm::ws::url( QMap params ) -{ - sign( params ); - QUrl url = ::baseUrl(); - // Qt setQueryItems doesn't encode a bunch of stuff, so we do it manually - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - QByteArray const key = QUrl::toPercentEncoding( i.key() ); - QByteArray const value = QUrl::toPercentEncoding( i.value() ); - url.addEncodedQueryItem( key, value ); - } - - return url; -} - - -QNetworkReply* -lastfm::ws::get( QMap params ) -{ - return nam()->get( QNetworkRequest( url( params ) ) ); -} - - -QNetworkReply* -lastfm::ws::post( QMap params, bool sk ) -{ - sign( params, sk ); - QByteArray query; - QMapIterator i( params ); - while (i.hasNext()) { - i.next(); - query += QUrl::toPercentEncoding( i.key() ) - + '=' - + QUrl::toPercentEncoding( i.value() ) - + '&'; - } - - QNetworkRequest req( baseUrl() ); - req.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" ); - return nam()->post( req, query ); -} - - -QNetworkAccessManager* -lastfm::nam() -{ - QMutexLocker l( &namAccessMutex ); - QThread* thread = QThread::currentThread(); - if ( !threadNamHash.contains( thread ) ) - { - NetworkAccessManager* newNam = new NetworkAccessManager(); - threadNamHash[thread] = newNam; - ourNamSet.insert( thread ); - return newNam; - } - return threadNamHash[thread]; -} - - -void -lastfm::setNetworkAccessManager( QNetworkAccessManager* nam ) -{ - if ( !nam ) - return; - - QMutexLocker l( &namAccessMutex ); - QThread* thread = QThread::currentThread(); - QNetworkAccessManager* oldNam = 0; - if ( threadNamHash.contains( thread ) && ourNamSet.contains( thread ) ) - oldNam = threadNamHash[thread]; - - if ( oldNam == nam ) - { - // If we're being passed back our own NAM, assume they want to - // ensure that we don't delete it out from under them - ourNamSet.remove( thread ); - return; - } - - threadNamHash[thread] = nam; - ourNamSet.remove( thread ); - - if ( oldNam ) - delete oldNam; -} - - -/** This useful function, fromHttpDate, comes from QNetworkHeadersPrivate - * in qnetworkrequest.cpp. Qt copyright and license apply. */ -static QDateTime QByteArrayToHttpDate(const QByteArray &value) -{ - // HTTP dates have three possible formats: - // RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT" - // RFC 850 - dddd, dd-MMM-yy hh:mm:ss "GMT" - // ANSI C's asctime - ddd MMM d hh:mm:ss yyyy - // We only handle them exactly. If they deviate, we bail out. - - int pos = value.indexOf(','); - QDateTime dt; - if (pos == -1) { - // no comma -> asctime(3) format - dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate); - } else { - // eat the weekday, the comma and the space following it - QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2); - - QLocale c = QLocale::c(); - if (pos == 3) - // must be RFC 1123 date - dt = c.toDateTime(sansWeekday, QLatin1String("dd MMM yyyy hh:mm:ss 'GMT")); - else - // must be RFC 850 date - dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'")); - } - - if (dt.isValid()) - dt.setTimeSpec(Qt::UTC); - return dt; -} - - -QDateTime -lastfm::ws::expires( QNetworkReply* reply ) -{ - return QByteArrayToHttpDate( reply->rawHeader( "Expires" ) ); -} - - -namespace lastfm -{ - namespace ws - { - QString SessionKey; - QString Username; - - /** we leave these unset as you can't use the webservices without them - * so lets make the programmer aware of it during testing by crashing */ - const char* SharedSecret; - const char* ApiKey; - - /** if this is found set to "" we conjure ourselves a suitable one */ - const char* UserAgent = 0; - } -} - - -QDebug operator<<( QDebug, lastfm::ws::Error ); diff --git a/thirdparty/liblastfm2/src/ws/ws.h b/thirdparty/liblastfm2/src/ws/ws.h deleted file mode 100644 index b9bb90e0c..000000000 --- a/thirdparty/liblastfm2/src/ws/ws.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright 2009 Last.fm Ltd. - - Primarily authored by Max Howell, Jono Cole and Doug Mansell - - This file is part of liblastfm. - - liblastfm is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - liblastfm is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with liblastfm. If not, see . -*/ -#ifndef LASTFM_WS_H -#define LASTFM_WS_H - -#include -#include -#include -#include -#include - -#ifdef Q_CC_MSVC -// ms admits its lousy compiler doesn't care about throw declarations -#pragma warning( disable : 4290 ) -#endif - - -namespace lastfm -{ - /** if you don't set one, we create our own, our own is pretty good - * for instance, it auto detects proxy settings on windows and mac - * We take ownership of the NAM, do not delete it out from underneath us! - * So don't keep any other pointers to this around in case you accidently - * call delete on them :P */ - LASTFM_DLLEXPORT void setNetworkAccessManager( QNetworkAccessManager* nam ); - LASTFM_DLLEXPORT QNetworkAccessManager* nam(); - - namespace ws - { - /** both of these are provided when you register at http://last.fm/api */ - LASTFM_DLLEXPORT extern const char* SharedSecret; - LASTFM_DLLEXPORT extern const char* ApiKey; - - /** you need to set this for scrobbling to work (for now) - * Also the AuthenticatedUser class uses it */ - LASTFM_DLLEXPORT extern QString Username; - - /** Some webservices require authentication. See the following - * documentation: - * http://www.last.fm/api/authentication - * http://www.last.fm/api/desktopauth - * You have to authenticate and then assign to SessionKey, liblastfm does - * not do that for you. Also we do not store this. You should store this! - * You only need to authenticate once, and that key lasts forever! - */ - LASTFM_DLLEXPORT extern QString SessionKey; - - enum Error - { - NoError = 1, // because last.fm error numbers start at 2 - - /** numbers follow those at http://last.fm/api/ */ - InvalidService = 2, - InvalidMethod, - AuthenticationFailed, - InvalidFormat, - InvalidParameters, - InvalidResourceSpecified, - OperationFailed, - InvalidSessionKey, - InvalidApiKey, - ServiceOffline, - SubscribersOnly, - - Reserved13, - Reserved14, - Reserved15, - - /** Last.fm sucks. - * There may be an error in networkError(), or this may just be some - * internal error completing your request. - * Advise the user to try again in a _few_minutes_. - * For some cases, you may want to try again yourself, at this point - * in the API you will have to. Eventually we will discourage this and - * do it for you, as we don't want to strain Last.fm's servers - */ - TryAgainLater = 16, - - Reserved17, - Reserved18, - Reserved19, - - NotEnoughContent = 20, - NotEnoughMembers, - NotEnoughFans, - NotEnoughNeighbours, - - /** Last.fm fucked up, or something mangled the response on its way */ - MalformedResponse = 100, - - /** call QNetworkReply::error() as it's nothing to do with us */ - UnknownError - }; - - LASTFM_DLLEXPORT QString host(); - - /** the map needs a method entry, as per http://last.fm/api */ - LASTFM_DLLEXPORT QUrl url( QMap ); - LASTFM_DLLEXPORT QNetworkReply* get( QMap ); - /** generates api sig, includes api key, and posts, don't add the api - * key yourself as well--it'll break */ - LASTFM_DLLEXPORT QNetworkReply* post( QMap, bool sessionKey = true ); - - - class ParseError : public std::runtime_error - { - Error e; - QString m_message; - public: - explicit ParseError( Error e, QString message ) - :std::runtime_error("lastfm::ws::Error"), e(e), m_message(message) - {} - Error enumValue() const { return e; } - QString message() const { return m_message; } - - ~ParseError() throw() {;} - }; - - /** returns the expiry date of this HTTP response */ - LASTFM_DLLEXPORT QDateTime expires( QNetworkReply* ); - } -} - - -inline QDebug operator<<( QDebug d, QNetworkReply::NetworkError e ) -{ - return d << lastfm::qMetaEnumString( e, "NetworkError" ); -} - -#define LASTFM_WS_HOSTNAME "ws.audioscrobbler.com" - -#endif diff --git a/thirdparty/liblastfm2/tests/TestTrack.h b/thirdparty/liblastfm2/tests/TestTrack.h deleted file mode 100644 index c771a45e9..000000000 --- a/thirdparty/liblastfm2/tests/TestTrack.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -using lastfm::Track; - -class TestTrack : public QObject -{ - Q_OBJECT - - Track example() - { - lastfm::MutableTrack t; - t.setTitle( "Test Title" ); - t.setArtist( "Test Artist" ); - t.setAlbum( "Test Album" ); - return t; - } - -private slots: - void testClone() - { - Track original = example(); - Track copy = original; - - #define TEST( x ) QVERIFY( original.x == copy.x ) - TEST( title() ); - TEST( artist() ); - TEST( album() ); - #undef TEST - } -}; diff --git a/thirdparty/liblastfm2/tests/TestUrlBuilder.h b/thirdparty/liblastfm2/tests/TestUrlBuilder.h deleted file mode 100644 index 909d10e37..000000000 --- a/thirdparty/liblastfm2/tests/TestUrlBuilder.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -#include -#include -#include - -static inline int getResponseCode( const QUrl& url ) -{ - QNetworkAccessManager nam; - QNetworkReply* reply = nam.head( QNetworkRequest(url) ); - - QEventLoop loop; - loop.connect( reply, SIGNAL(finished()), SLOT(quit()) ); - loop.exec(); - - int const code = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); - - if (reply->error() != QNetworkReply::NoError) - qDebug() << url << lastfm::qMetaEnumString( reply->error(), "NetworkError" ) << code; - - return code; -} - - -class TestUrlBuilder : public QObject -{ - Q_OBJECT - -private slots: - void encode() /** @author */ - { - QFETCH( QString, input ); - QFETCH( QString, output ); - QCOMPARE( lastfm::UrlBuilder::encode( input ), output.toAscii() ); - } - - void encode_data() /** @author */ - { - QTest::addColumn("input"); - QTest::addColumn("output"); - - QTest::newRow( "ascii" ) << "Metallica" << "Metallica"; - QTest::newRow( "ascii alphanumeric" ) << "Apollo 440" << "Apollo+440"; - QTest::newRow( "ascii with symbols" ) << "some track [original version]" << "some+track+%5Boriginal+version%5D"; - QTest::newRow( "ascii with last.fm-special symbols" ) << "Survivalism [Revision #1]" << "Survivalism%2B%255BRevision%2B%25231%255D"; - } - - void no404() /** @author */ - { - QFETCH( QString, artist ); - QFETCH( QString, track ); - - QUrl url = lastfm::UrlBuilder( "music" ).slash( artist ).slash( "_" ).slash( track ).url(); - - QCOMPARE( getResponseCode( url ), 200 ); - } - - void no404_data() /** @author */ - { - QTest::addColumn("artist"); - QTest::addColumn("track"); - - #define NEW_ROW( x, y ) QTest::newRow( x " - " y ) << x << y; - NEW_ROW( "Air", "Radio #1" ); - NEW_ROW( "Pink Floyd", "Speak to Me / Breathe" ); - NEW_ROW( "Radiohead", "2 + 2 = 5" ); - NEW_ROW( "Above & Beyond", "World On Fire (Maor Levi Remix)" ); - #undef NEW_ROW - } - - void test404() /** @author */ - { - QCOMPARE( getResponseCode( QUrl("http://www.last.fm/404") ), 404 ); - } -}; diff --git a/thirdparty/liblastfm2/tests/main.cpp b/thirdparty/liblastfm2/tests/main.cpp deleted file mode 100644 index 5995bffa2..000000000 --- a/thirdparty/liblastfm2/tests/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - This software is in the public domain, furnished "as is", without technical - support, and with no warranty, express or implied, as to its usefulness for - any purpose. -*/ -#include -#include -#include "TestTrack.h" -#include "TestUrlBuilder.h" - -int main( int argc, char** argv) -{ - QCoreApplication app( argc, argv ); - - #define TEST( Type ) { \ - Type o; \ - if (int r = QTest::qExec( &o, argc, argv ) != 0) return r; } - - TEST( TestTrack ); - TEST( TestUrlBuilder ); - return 0; -} diff --git a/thirdparty/liblastfm2/tests/tests.pro b/thirdparty/liblastfm2/tests/tests.pro deleted file mode 100644 index da65f1cde..000000000 --- a/thirdparty/liblastfm2/tests/tests.pro +++ /dev/null @@ -1,4 +0,0 @@ -QT = core testlib network xml -LIBS += -llastfm -L$$DESTDIR -SOURCES = main.cpp -HEADERS = TestTrack.h TestUrlBuilder.h \ No newline at end of file From 4f261b17113d579d9e4e6a3dc8635e9b494d6557 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 11 Jun 2012 21:10:46 +0200 Subject: [PATCH 355/433] * Removed liblastfm2 from thirdparty/CMakeLists.txt. --- thirdparty/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 9612d4e16..7aa197296 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,5 +1,4 @@ ADD_SUBDIRECTORY( qxt ) -ADD_SUBDIRECTORY( liblastfm2 ) IF( WITH_BREAKPAD ) ADD_SUBDIRECTORY( breakpad ) ENDIF() From d16c608610112267474a2b61157f588c4b8afa72 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 11 Jun 2012 21:13:44 +0200 Subject: [PATCH 356/433] * Fixed CMakeLists.txt. --- src/CMakeLists.txt | 3 +-- src/libtomahawk/CMakeLists.txt | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f283094f5..d58d76de2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,7 +96,6 @@ SET( tomahawkUI ${tomahawkUI} INCLUDE_DIRECTORIES( . ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src audio database @@ -181,7 +180,7 @@ MESSAGE( STATUS "OS_SPECIFIC_LINK_LIBRARIES: ${OS_SPECIFIC_LINK_LIBRARIES}" ) SET(LINK_LIBRARIES "") IF(LIBLASTFM_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_lastfm2 ) + SET(LINK_LIBRARIES ${LINK_LIBRARIES} lastfm ) ENDIF(LIBLASTFM_FOUND) IF(QCA2_FOUND) SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index cd58acc37..b85466c97 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -6,6 +6,10 @@ SET( QT_USE_QTNETWORK TRUE ) SET( QT_USE_QTXML TRUE ) SET( QT_USE_QTUITOOLS TRUE ) +IF( UNIX AND NOT APPLE ) + SET( QT_USE_QTDBUS TRUE ) +ENDIF( UNIX AND NOT APPLE ) + include( ${QT_USE_FILE} ) add_definitions( ${QT_DEFINITIONS} ) @@ -327,7 +331,6 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/. ${LIBECHONEST_INCLUDE_DIR}/.. ${CLUCENE_INCLUDE_DIRS} ${PHONON_INCLUDES} - ${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src playlist @@ -398,7 +401,7 @@ ELSE( APPLE ) ENDIF( APPLE ) IF(LIBLASTFM_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_lastfm2 ) + SET(LINK_LIBRARIES ${LINK_LIBRARIES} lastfm ) ENDIF(LIBLASTFM_FOUND) IF(BUILD_GUI) @@ -420,6 +423,10 @@ IF(LIBATTICA_FOUND) SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBATTICA_LIBRARIES} ${QuaZip_LIBRARIES} ) ENDIF(LIBATTICA_FOUND) +IF( UNIX AND NOT APPLE ) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${QT_QTDBUS_LIBRARY} ) +ENDIF( UNIX AND NOT APPLE ) + TARGET_LINK_LIBRARIES( tomahawklib # Thirdparty shipped with tomahawk ${LIBPORTFWD_LIBRARIES} From a9a86f8043ed419b7557e60a8059dae6d79a6940 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 11 Jun 2012 21:14:21 +0200 Subject: [PATCH 357/433] * Fixed usage of new liblastfm. --- src/Scrobbler.cpp | 4 ++-- src/Scrobbler.h | 4 ++-- src/TomahawkApp.h | 2 +- src/libtomahawk/accounts/lastfm/LastFmConfig.cpp | 12 +++++++----- src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp | 10 ++++++---- src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h | 6 +++--- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Scrobbler.cpp b/src/Scrobbler.cpp index 8c3285161..6e1b77bc3 100644 --- a/src/Scrobbler.cpp +++ b/src/Scrobbler.cpp @@ -99,9 +99,9 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) // liblastfm forces 0-length tracks to scrobble after 4 minutes, stupid. if ( track->duration() == 0 ) - m_scrobblePoint = ScrobblePoint( 30 ); + m_scrobblePoint = lastfm::ScrobblePoint( 30 ); else - m_scrobblePoint = ScrobblePoint( track->duration() / 2 ); + m_scrobblePoint = lastfm::ScrobblePoint( track->duration() / 2 ); } diff --git a/src/Scrobbler.h b/src/Scrobbler.h index d47e34d1f..5d92bfbb1 100644 --- a/src/Scrobbler.h +++ b/src/Scrobbler.h @@ -20,7 +20,7 @@ #ifndef TOMAHAWK_SCROBBLER_H #define TOMAHAWK_SCROBBLER_H -#include "lastfm/ScrobblePoint" +#include "lastfm/ScrobblePoint.h" #include "Result.h" #include "infosystem/InfoSystem.h" @@ -51,7 +51,7 @@ private: void scrobble(); bool m_reachedScrobblePoint; - ScrobblePoint m_scrobblePoint; + lastfm::ScrobblePoint m_scrobblePoint; }; diff --git a/src/TomahawkApp.h b/src/TomahawkApp.h index 41cfae3a9..417bc3094 100644 --- a/src/TomahawkApp.h +++ b/src/TomahawkApp.h @@ -64,7 +64,7 @@ namespace Tomahawk } #ifdef LIBLASTFM_FOUND -#include +#include #include "Scrobbler.h" #endif diff --git a/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp index c9fdcf357..354f6b92e 100644 --- a/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp +++ b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp @@ -25,8 +25,8 @@ #include "utils/TomahawkUtils.h" #include "utils/Logger.h" #include "lastfm/ws.h" -#include "lastfm/User" -#include "lastfm/XmlQuery" +#include "lastfm/User.h" +#include "lastfm/XmlQuery.h" using namespace Tomahawk::Accounts; @@ -135,7 +135,8 @@ LastFmConfig::onHistoryLoaded() try { - lastfm::XmlQuery lfm = reply->readAll(); + lastfm::XmlQuery lfm; + lfm.parse( reply->readAll() ); foreach ( lastfm::XmlQuery e, lfm.children( "track" ) ) { @@ -170,7 +171,7 @@ LastFmConfig::onHistoryLoaded() } catch( lastfm::ws::ParseError e ) { - tDebug() << "XmlQuery error:" << e.what(); + tDebug() << "XmlQuery error:" << e.message(); finished = true; } @@ -200,7 +201,8 @@ LastFmConfig::onLastFmFinished() } if( authJob->error() == QNetworkReply::NoError ) { - lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() ); + lastfm::XmlQuery lfm; + lfm.parse( authJob->readAll() ); if( lfm.children( "error" ).size() > 0 ) { diff --git a/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp index 30aed0d06..40f67a9e7 100644 --- a/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp +++ b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.cpp @@ -34,7 +34,7 @@ #include "TomahawkSettings.h" #include -#include +#include #include @@ -871,7 +871,8 @@ LastFmInfoPlugin::onAuthenticated() if ( authJob->error() == QNetworkReply::NoError ) { - lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() ); + lastfm::XmlQuery lfm; + lfm.parse( authJob->readAll() ); if ( lfm.children( "error" ).size() > 0 ) { @@ -933,7 +934,8 @@ LastFmInfoPlugin::parseTrackList( QNetworkReply* reply ) QList tracks; try { - lastfm::XmlQuery lfm = reply->readAll(); + lastfm::XmlQuery lfm; + lfm.parse( reply->readAll() ); foreach ( lastfm::XmlQuery xq, lfm.children( "track" ) ) { tracks.append( lastfm::Track( xq ) ); @@ -941,7 +943,7 @@ LastFmInfoPlugin::parseTrackList( QNetworkReply* reply ) } catch ( lastfm::ws::ParseError& e ) { - qWarning() << e.what(); + qWarning() << e.message(); } return tracks; diff --git a/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h index f744c740e..f8bbacd17 100644 --- a/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h +++ b/src/libtomahawk/accounts/lastfm/LastFmInfoPlugin.h @@ -24,9 +24,9 @@ #include "infosystem/InfoSystemWorker.h" #include "DllMacro.h" -#include -#include -#include +#include +#include +#include #include From 695feed2b6e81ca284087e0564fbc5175c8e3d3c Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Tue, 12 Jun 2012 02:23:38 +0200 Subject: [PATCH 358/433] Include Qt translations --- lang/translations.cmake | 65 ++++++++++++++++++++++++++++------------- src/CMakeLists.txt | 2 ++ src/TomahawkApp.cpp | 18 ++++++++++-- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/lang/translations.cmake b/lang/translations.cmake index a5b92f2f4..6b4f89557 100644 --- a/lang/translations.cmake +++ b/lang/translations.cmake @@ -1,25 +1,48 @@ -FILE (GLOB TS_FILES ${CMAKE_SOURCE_DIR}/lang/*.ts) -QT4_ADD_TRANSLATION(QM_FILES ${TS_FILES}) +macro(add_tomahawk_translations language) + list(APPEND TOMAHAWK_LANGUAGES ${ARGV}) -## HACK HACK HACK - around rcc limitations to allow out of source-tree building -SET( trans_file tomahawk_i18n ) -SET( trans_srcfile ${CMAKE_SOURCE_DIR}/lang/${trans_file}.qrc) -SET( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc) -SET( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${trans_file}.cxx) + set(tomahawk_i18n_qrc_content "\n") -# Copy the QRC file to the output directory -ADD_CUSTOM_COMMAND( - OUTPUT ${trans_infile} - COMMAND ${CMAKE_COMMAND} -E copy ${trans_srcfile} ${trans_infile} - MAIN_DEPENDENCY ${trans_srcfile} -) + # tomahawk and qt language files + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}\n") + foreach(lang ${TOMAHAWK_LANGUAGES}) + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}tomahawk_${lang}.qm\n") + if(NOT lang STREQUAL "en" AND EXISTS ${QT_TRANSLATIONS_DIR}/qt_${lang}.qm) + file(COPY ${QT_TRANSLATIONS_DIR}/qt_${lang}.qm DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}qt_${lang}.qm\n") + endif() -# Run the resource compiler (rcc_options should already be set) -ADD_CUSTOM_COMMAND( - OUTPUT ${trans_outfile} - COMMAND ${QT_RCC_EXECUTABLE} - ARGS ${rcc_options} -name ${trans_file} -o ${trans_outfile} ${trans_infile} - MAIN_DEPENDENCY ${trans_infile} - DEPENDS ${QM_FILES} -) + # build explicitly enabled languages + list(APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/tomahawk_${lang}.ts") + endforeach() + + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}\n") + set(tomahawk_i18n_qrc_content "${tomahawk_i18n_qrc_content}\n") + + file(WRITE ${CMAKE_BINARY_DIR}/lang/tomahawk_i18n.qrc "${tomahawk_i18n_qrc_content}" ) + + QT4_ADD_TRANSLATION(QM_FILES ${TS_FILES}) + + ## HACK HACK HACK - around rcc limitations to allow out of source-tree building + SET( trans_file tomahawk_i18n ) + SET( trans_srcfile ${CMAKE_BINARY_DIR}/lang/${trans_file}.qrc) + SET( trans_infile ${CMAKE_CURRENT_BINARY_DIR}/${trans_file}.qrc) + SET( trans_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${trans_file}.cxx) + + # Copy the QRC file to the output directory + ADD_CUSTOM_COMMAND( + OUTPUT ${trans_infile} + COMMAND ${CMAKE_COMMAND} -E copy ${trans_srcfile} ${trans_infile} + MAIN_DEPENDENCY ${trans_srcfile} + ) + + # Run the resource compiler (rcc_options should already be set) + ADD_CUSTOM_COMMAND( + OUTPUT ${trans_outfile} + COMMAND ${QT_RCC_EXECUTABLE} + ARGS ${rcc_options} -name ${trans_file} -o ${trans_outfile} ${trans_infile} + MAIN_DEPENDENCY ${trans_infile} + DEPENDS ${QM_FILES} + ) +endmacro() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d58d76de2..aa799cfc9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -145,7 +145,9 @@ INCLUDE(GNUInstallDirs) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) +# translations include( ${CMAKE_SOURCE_DIR}/lang/translations.cmake ) +add_tomahawk_translations(ar bg ca de en es fr ja pl pt_BR ru sv tr zh_CN zh_TW) SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${trans_outfile}) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index baf919ee1..f3ac2a95c 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -141,18 +141,32 @@ TomahawkApp::installTranslator() if ( locale == "C" ) locale = "en"; + // Tomahawk translations QTranslator* translator = new QTranslator( this ); if ( translator->load( QString( ":/lang/tomahawk_" ) + locale ) ) { - tDebug() << "Using system locale:" << locale; + tDebug() << "Translation: Tomahawk: Using system locale:" << locale; } else { - tDebug() << "Using default locale, system locale one not found:" << locale; + tDebug() << "Translation: Tomahawk: Using default locale, system locale one not found:" << locale; translator->load( QString( ":/lang/tomahawk_en" ) ); } TOMAHAWK_APPLICATION::installTranslator( translator ); + + // Qt translations + translator = new QTranslator( this ); + if ( translator->load( QString( ":/lang/qt_" ) + locale ) ) + { + tDebug() << "Translation: Qt: Using system locale:" << locale; + } + else + { + tDebug() << "Translation: Qt: Using default locale, system locale one not found:" << locale; + } + + TOMAHAWK_APPLICATION::installTranslator( translator ); } From 88ea5f78552f96b4a0b9c16a2f03bb065783c749 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 00:47:27 +0200 Subject: [PATCH 359/433] * Fixed macdeploy scripts for VLC2 and Qt 4.8.2. --- admin/mac/macdeploy.py | 6 +++--- admin/mac/qt.conf | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/mac/macdeploy.py b/admin/mac/macdeploy.py index f6ab64641..bf859e346 100755 --- a/admin/mac/macdeploy.py +++ b/admin/mac/macdeploy.py @@ -206,7 +206,7 @@ TOMAHAWK_PLUGINS = [ ] QT_PLUGINS_SEARCH_PATH=[ - '/usr/local/Cellar/qt/4.7.4/plugins', + '/usr/local/Cellar/qt/4.8.2/plugins', ] @@ -249,7 +249,7 @@ frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks') commands.append(['mkdir', '-p', frameworks_dir]) resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources') commands.append(['mkdir', '-p', resources_dir]) -plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns') +plugins_dir = os.path.join(bundle_dir, 'Contents', 'qt-plugins') binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name) fixed_libraries = [] @@ -489,7 +489,7 @@ def FindVLCPlugin(name): FixBinary(binary) for plugin in VLC_PLUGINS: - FixVLCPlugin(FindVLCPlugin(plugin), '../Frameworks/vlc/plugins') + FixVLCPlugin(FindVLCPlugin(plugin), '../plugins') for plugin in TOMAHAWK_PLUGINS: FixPlugin(plugin, '../MacOS') diff --git a/admin/mac/qt.conf b/admin/mac/qt.conf index 64d729736..d0e7835ac 100644 --- a/admin/mac/qt.conf +++ b/admin/mac/qt.conf @@ -1,2 +1,2 @@ [Paths] -Plugins = PlugIns +Plugins = qt-plugins From 14ab48ae36243b19e7e0b67feab4f7b5a4ad1fa1 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Mon, 11 Jun 2012 22:56:16 +0000 Subject: [PATCH 360/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 18 +++++++++--------- lang/tomahawk_bg.ts | 18 +++++++++--------- lang/tomahawk_ca.ts | 18 +++++++++--------- lang/tomahawk_de.ts | 18 +++++++++--------- lang/tomahawk_en.ts | 18 +++++++++--------- lang/tomahawk_es.ts | 18 +++++++++--------- lang/tomahawk_fr.ts | 18 +++++++++--------- lang/tomahawk_ja.ts | 18 +++++++++--------- lang/tomahawk_pl.ts | 18 +++++++++--------- lang/tomahawk_pt_BR.ts | 18 +++++++++--------- lang/tomahawk_ru.ts | 18 +++++++++--------- lang/tomahawk_sv.ts | 18 +++++++++--------- lang/tomahawk_tr.ts | 18 +++++++++--------- lang/tomahawk_zh_CN.ts | 18 +++++++++--------- lang/tomahawk_zh_TW.ts | 18 +++++++++--------- 15 files changed, 135 insertions(+), 135 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index ca51f99ba..72fa376ff 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -1628,12 +1628,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required مطلوب تثبيت يدوي - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على منصتك. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1714,28 +1714,28 @@ connect and stream from you? نقل التاريخ... - + History Incomplete. Resume تاريخ ناقص. استأنف - + Playback History Imported تم استيراد تاريخ إعادة الإستماع - - + + Failed فشلت - + Success نجاح - + Could not contact server لم أستطيع الإتصال بالخادم @@ -2798,7 +2798,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection مجموعتي الخاصة diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index e98480f43..8160aded9 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -1631,12 +1631,12 @@ Tomahaw създаде доклад относно това и изпращай Tomahawk::Accounts::AccountModel - + Manual Install Required Изисква се ръчно инсталиране - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 За съжаление, автоматичното инсталиране на този компонен е деактивирано за твоята платформа. <br /><br /> @@ -1720,28 +1720,28 @@ Tomahaw създаде доклад относно това и изпращай Импортирам... - + History Incomplete. Resume Непълна информация. Продължи. - + Playback History Imported Историята на просвирените песни е импортирана - - + + Failed Неуспешно - + Success Ура! - + Could not contact server Не мога да се свържа със сървъра @@ -2805,7 +2805,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моята колекция diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index a22796f72..5378b9648 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -1627,12 +1627,12 @@ i emissores de ràdio basades en el vostre gust musical. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1713,28 +1713,28 @@ i emissores de ràdio basades en el vostre gust musical. - + History Incomplete. Resume - + Playback History Imported - - + + Failed Error - + Success Èxit - + Could not contact server No s'ha pogut contactar amb el servidor @@ -2797,7 +2797,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. TomahawkApp - + My Collection La meva Col·lecció diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 4fadc0e53..d3158a31b 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -1624,12 +1624,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manuelle Installation benötigt - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1710,28 +1710,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed Fehlgeschlagen - + Success Erfolgreich - + Could not contact server Konnte den Server nicht erreichen! @@ -2792,7 +2792,7 @@ Versuch die Filter anzupassen für neue Lieder. TomahawkApp - + My Collection Meine Sammlung diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 0e1899083..fd34c8768 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -1628,12 +1628,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1714,28 +1714,28 @@ connect and stream from you? Importing History... - + History Incomplete. Resume History Incomplete. Resume - + Playback History Imported Playback History Imported - - + + Failed Failed - + Success Success - + Could not contact server Could not contact server @@ -2798,7 +2798,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection My Collection diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 71e1dc0d7..6dc67a608 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -1626,12 +1626,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1712,28 +1712,28 @@ y estaciones basadas en sus gustos personales. - + History Incomplete. Resume - + Playback History Imported - - + + Failed Fallo - + Success Éxito - + Could not contact server No se pudo contactar el servidor @@ -2796,7 +2796,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. TomahawkApp - + My Collection Mi colección diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index dbb14fbdf..66baafa21 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -1628,12 +1628,12 @@ et des stations basées sur vos goûts. Tomahawk::Accounts::AccountModel - + Manual Install Required Installation manuelle requise - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Malheureusement, l'installation automatique de ce script de résolution n'est pas disponible ou a été désactivé sur votre plateforme.<br /><br />Utiliser "Installer depuis un fichier" ci-dessus et téléchargez le fichier pour votre distribution, ou compilez-le. D'autres instructions sont disponibles ici :<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1714,28 +1714,28 @@ et des stations basées sur vos goûts. Import de l'historique... - + History Incomplete. Resume Historique incomplet. Reprendre - + Playback History Imported Historique de lecture importé - - + + Failed Échec - + Success Succès - + Could not contact server Impossible de contacter le serveur @@ -2798,7 +2798,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. TomahawkApp - + My Collection Ma Collection diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index d9c300296..cf7d4f67d 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -1625,12 +1625,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1711,28 +1711,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -2788,7 +2788,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 970beaa82..d1e41f35b 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -1627,12 +1627,12 @@ indywidualnego profilu gustu. Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1713,28 +1713,28 @@ indywidualnego profilu gustu. - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -2792,7 +2792,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Moja Kolekcja diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index ea03d2230..3838d9104 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -1626,12 +1626,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1712,28 +1712,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed Falhou - + Success Sucesso - + Could not contact server @@ -2791,7 +2791,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Minha biblioteca diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 2a6ae3d9c..0d441c384 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -1625,12 +1625,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1711,28 +1711,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed Неудача - + Success Успех - + Could not contact server Не удается связаться с сервером @@ -2793,7 +2793,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection Моя коллекция diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 5944d6c16..88f4ccce8 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1624,12 +1624,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1710,28 +1710,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -2787,7 +2787,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index fab909847..da813a754 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -1623,12 +1623,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1709,28 +1709,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -2786,7 +2786,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index fa2f64bb5..25858013b 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -1623,12 +1623,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1709,28 +1709,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed - + Success - + Could not contact server @@ -2786,7 +2786,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index bfe2f4f67..0ba0ae65d 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -1623,12 +1623,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 @@ -1709,28 +1709,28 @@ connect and stream from you? - + History Incomplete. Resume - + Playback History Imported - - + + Failed 失敗 - + Success 成功 - + Could not contact server 無法聯繫服務器 @@ -2786,7 +2786,7 @@ Try tweaking the filters for a new set of songs to play. TomahawkApp - + My Collection 我的收藏 From 3b7a057dbb86ace64c0bfadfe3c6656ed8d0dc8c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 00:57:03 +0200 Subject: [PATCH 361/433] * Added infoplugins to DMG. --- admin/mac/macdeploy.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/admin/mac/macdeploy.py b/admin/mac/macdeploy.py index bf859e346..8acda2049 100755 --- a/admin/mac/macdeploy.py +++ b/admin/mac/macdeploy.py @@ -203,6 +203,16 @@ TOMAHAWK_PLUGINS = [ 'libtomahawk_account_google.so', 'libtomahawk_account_twitter.so', 'libtomahawk_account_zeroconf.so', + 'libtomahawk_infoplugin_adium.so', + 'libtomahawk_infoplugin_charts.so', + 'libtomahawk_infoplugin_discogs.so', + 'libtomahawk_infoplugin_echonest.so', + 'libtomahawk_infoplugin_hypem.so', + 'libtomahawk_infoplugin_musicbrainz.so', + 'libtomahawk_infoplugin_musixmatch.so', + 'libtomahawk_infoplugin_newreleases.so', + 'libtomahawk_infoplugin_rovi.so', + 'libtomahawk_infoplugin_spotify.so', ] QT_PLUGINS_SEARCH_PATH=[ From cc320a99f26a4ef16785dcbf67a44d9fdbe389fb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 01:12:33 +0200 Subject: [PATCH 362/433] * Check for liblastfm 1.0.0 being available. --- CMakeLists.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8f136639..12535f17c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) # make predefined install dirs available everywhere -INCLUDE(GNUInstallDirs) +INCLUDE( GNUInstallDirs ) # installer creation INCLUDE( TomahawkCPack.cmake ) @@ -133,11 +133,8 @@ macro_log_feature(JREEN_FOUND "Jreen" "Qt XMPP Library" "http://qutim.org/jreen macro_optional_find_package(QTweetLib) macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin.\n") -# required -#While we distribute our own liblastfm2, don't need to look for it -#macro_optional_find_package(LibLastFm 0.3.3) -#macro_log_feature(LIBLASTFM_FOUND "LastFm" "Qt library for the Last.fm webservices" "https://github.com/mxcl/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") -set(LIBLASTFM_FOUND true) +macro_optional_find_package(LibLastFm 1.0.0) +macro_log_feature(LIBLASTFM_FOUND "liblastfm" "Qt library for the Last.fm webservices" "https://github.com/eartle/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") #### submodules start # automatically init submodules here, don't delete this code we may add submodules again From 5e731953a3b34e7b838cc7b5957a455eb45e1f33 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 01:18:07 +0200 Subject: [PATCH 363/433] * Fixed FindLibLastFm.cmak comments. --- CMakeModules/FindLibLastFm.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeModules/FindLibLastFm.cmake b/CMakeModules/FindLibLastFm.cmake index e7cd40134..1997d75a7 100644 --- a/CMakeModules/FindLibLastFm.cmake +++ b/CMakeModules/FindLibLastFm.cmake @@ -1,8 +1,8 @@ # - Try to find LibLastFm # -# LIBLASTFM_FOUND - system has QTweetLib -# LIBLASTFM_INCLUDE_DIRS - the QTweetLib include directories -# LIBLASTFM_LIBRARIES - link these to use QTweetLib +# LIBLASTFM_FOUND - system has liblastfm +# LIBLASTFM_INCLUDE_DIRS - the liblastfm include directories +# LIBLASTFM_LIBRARIES - link these to use liblastfm # # (c) Dominik Schmidt # From 6c94e2528654837d0b0dd9525d48f7094a0ff688 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 01:21:09 +0200 Subject: [PATCH 364/433] * Fixed FindLibLastFm.cmake. --- CMakeModules/FindLibLastFm.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeModules/FindLibLastFm.cmake b/CMakeModules/FindLibLastFm.cmake index 1997d75a7..27362fe71 100644 --- a/CMakeModules/FindLibLastFm.cmake +++ b/CMakeModules/FindLibLastFm.cmake @@ -26,7 +26,7 @@ find_library(LIBLASTFM_LIBRARY ) set(LIBLASTFM_LIBRARIES ${LIBLASTFM_LIBRARY}) -set(LIBLASTFM_INCLUDE_DIRS ${LIBLASTFM_LIBRARY}) +set(LIBLASTFM_INCLUDE_DIRS ${LIBLASTFM_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LibLastFm DEFAULT_MSG LIBLASTFM_LIBRARIES LIBLASTFM_INCLUDE_DIRS) From a1ef4c252c13d422b0f7b472836ef332f2d60b4b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 01:21:25 +0200 Subject: [PATCH 365/433] * Use proper CMake variables for liblastfm. --- src/CMakeLists.txt | 8 +++++--- src/libtomahawk/CMakeLists.txt | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa799cfc9..d014d65bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,6 +117,8 @@ INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR}/.. + ${LIBLASTFM_INCLUDE_DIRS} + ${LIBLASTFM_INCLUDE_DIRS}/.. ) SET( OS_SPECIFIC_LINK_LIBRARIES "" ) @@ -182,13 +184,13 @@ MESSAGE( STATUS "OS_SPECIFIC_LINK_LIBRARIES: ${OS_SPECIFIC_LINK_LIBRARIES}" ) SET(LINK_LIBRARIES "") IF(LIBLASTFM_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} lastfm ) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBLASTFM_LIBRARIES} ) ENDIF(LIBLASTFM_FOUND) IF(QCA2_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) ENDIF(QCA2_FOUND) IF(WITH_BREAKPAD) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad) + SET( LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad ) ENDIF() TARGET_LINK_LIBRARIES( tomahawk diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index b85466c97..2c0e5433c 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -329,6 +329,8 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/. ${QJSON_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR} ${LIBECHONEST_INCLUDE_DIR}/.. + ${LIBLASTFM_INCLUDE_DIRS} + ${LIBLASTFM_INCLUDE_DIRS}/.. ${CLUCENE_INCLUDE_DIRS} ${PHONON_INCLUDES} @@ -401,7 +403,7 @@ ELSE( APPLE ) ENDIF( APPLE ) IF(LIBLASTFM_FOUND) - SET(LINK_LIBRARIES ${LINK_LIBRARIES} lastfm ) + SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBLASTFM_LIBRARIES} ) ENDIF(LIBLASTFM_FOUND) IF(BUILD_GUI) From 9093068504f54487ba89f378e6dab6fa8e6b04fb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 04:42:48 +0200 Subject: [PATCH 366/433] * Fixed size for share / love buttons. --- src/AudioControls.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index a286bf9c5..eccffa918 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -88,6 +88,9 @@ AudioControls::AudioControls( QWidget* parent ) ui->socialButton->setPixmap( RESPATH "images/share.png" ); ui->loveButton->setPixmap( RESPATH "images/not-loved.png" ); ui->loveButton->setCheckable( true ); + + ui->socialButton->setFixedSize( QSize( 20, 20 ) ); + ui->loveButton->setFixedSize( QSize( 20, 20 ) ); #ifdef Q_WS_MAC ui->ownerLabel->setForegroundRole( QPalette::Text ); From 13c22e0c72e9dcb3d8e8bd5a2981fc7ec463a24b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 04:43:11 +0200 Subject: [PATCH 367/433] * Extra safety for AudioEngine. --- src/libtomahawk/audio/AudioEngine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 755875614..773adbb6d 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -342,6 +342,9 @@ AudioEngine::sendWaitingNotification() const void AudioEngine::sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type ) { + if ( m_currentTrack.isNull() ) + return; + #ifndef ENABLE_HEADLESS if ( m_currentTrack->toQuery()->coverLoaded() ) { From 9c1f2009050c31f9d6df19092b373ac651431c7c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 05:11:47 +0200 Subject: [PATCH 368/433] * Support posting to all TwitterInfoPlugins. --- src/accounts/twitter/TwitterInfoPlugin.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/accounts/twitter/TwitterInfoPlugin.cpp b/src/accounts/twitter/TwitterInfoPlugin.cpp index 39e375f0a..add608f33 100644 --- a/src/accounts/twitter/TwitterInfoPlugin.cpp +++ b/src/accounts/twitter/TwitterInfoPlugin.cpp @@ -76,15 +76,15 @@ TwitterInfoPlugin::~TwitterInfoPlugin() bool TwitterInfoPlugin::refreshTwitterAuth() { - tDebug() << Q_FUNC_INFO << " begin" << this; - if( !m_twitterAuth.isNull() ) + tDebug() << Q_FUNC_INFO << "begin" << this; + if ( !m_twitterAuth.isNull() ) delete m_twitterAuth.data(); Q_ASSERT( TomahawkUtils::nam() != 0 ); - tDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam() << this; + tDebug() << Q_FUNC_INFO << "with nam" << TomahawkUtils::nam() << this; m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) ); - if( m_twitterAuth.isNull() ) + if ( m_twitterAuth.isNull() ) return false; m_twitterAuth.data()->setOAuthToken( m_account->credentials()[ "oauthtoken" ].toString().toLatin1() ); @@ -138,7 +138,8 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) return; } - if ( !map[ "accountlist" ].toStringList().contains( m_account->accountId() ) ) + const QStringList accountList = map[ "accountlist" ].toStringList(); + if ( !accountList.contains( "all" ) && !accountList.contains( m_account->accountId() ) ) { tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Our account not in the list, not tweeting out"; return; @@ -168,7 +169,7 @@ TwitterInfoPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( m_twitterAuth.data(), this ); connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postLovedStatusUpdateReply(const QTweetStatus &) ) ); connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postLovedStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) ); - tDebug() << Q_FUNC_INFO << "Posting message: " << msg; + tDebug() << Q_FUNC_INFO << "Posting message:" << msg; statUpdate->post( msg ); } From 745ccd34ffda30d8bff89677e84a869856c4ad60 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 05:12:08 +0200 Subject: [PATCH 369/433] * Hard-coded posting to Twitter in SocialWidget. --- src/SocialWidget.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index 80f708939..09cad1014 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -229,6 +229,20 @@ void SocialWidget::accept() { tDebug() << "Sharing social link!"; + + QVariantMap shareInfo; + Tomahawk::InfoSystem::InfoStringHash trackInfo; + + trackInfo["title"] = m_query->track(); + trackInfo["artist"] = m_query->artist(); + trackInfo["album"] = m_query->album(); + + shareInfo["trackinfo"] = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); + shareInfo["message"] = ui->textEdit->toPlainText(); + shareInfo["accountlist"] = QStringList( "all" ); + + Tomahawk::InfoSystem::InfoPushData pushData( uuid(), Tomahawk::InfoSystem::InfoShareTrack, shareInfo, Tomahawk::InfoSystem::PushNoFlag ); + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData ); deleteLater(); } From caaec5c1c82aee752c1ef72ef6add46603311bfb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 05:12:24 +0200 Subject: [PATCH 370/433] * Style cleanup. --- src/libtomahawk/Typedefs.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/Typedefs.h b/src/libtomahawk/Typedefs.h index e442f2328..730799e9a 100644 --- a/src/libtomahawk/Typedefs.h +++ b/src/libtomahawk/Typedefs.h @@ -99,10 +99,11 @@ namespace Tomahawk typedef QList< SerializedUpdater > SerializedUpdaterList; - namespace InfoSystem { - - - enum InfoType { // as items are saved in cache, mark them here to not change them + namespace InfoSystem + { + enum InfoType + { + // as items are saved in cache, mark them here to not change them InfoNoInfo = 0, //WARNING: *ALWAYS* keep this first! InfoTrackID = 1, InfoTrackArtist = 2, From 2bb175860b7d982e9dcacaa7c5de71b0b955f042 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 05:18:27 +0200 Subject: [PATCH 371/433] * Prevent more than one SocialWidget showing up at a time. --- src/AudioControls.cpp | 11 +++++++---- src/AudioControls.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index eccffa918..43c2cb1a0 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -600,10 +600,13 @@ AudioControls::droppedTracks( QList< query_ptr > tracks ) void AudioControls::onSocialButtonClicked() { - SocialWidget* sw = new SocialWidget( m_parent ); - sw->setPosition( sw->mapFromGlobal( QCursor::pos() ) ); - sw->setQuery( m_currentTrack->toQuery() ); - sw->show(); + if ( !m_socialWidget.isNull() ) + return; + + m_socialWidget = new SocialWidget( m_parent ); + m_socialWidget.data()->setPosition( m_socialWidget.data()->mapFromGlobal( QCursor::pos() ) ); + m_socialWidget.data()->setQuery( m_currentTrack->toQuery() ); + m_socialWidget.data()->show(); } diff --git a/src/AudioControls.h b/src/AudioControls.h index d454bf2fe..aad7af1b9 100644 --- a/src/AudioControls.h +++ b/src/AudioControls.h @@ -31,6 +31,7 @@ class QDropEvent; class QDragEnterEvent; class QDragMoveEvent; +class SocialWidget; namespace Ui { @@ -91,6 +92,8 @@ private: void setSocialActions(); Ui::AudioControls* ui; + + QWeakPointer m_socialWidget; Tomahawk::result_ptr m_currentTrack; Tomahawk::PlaylistModes::RepeatMode m_repeatMode; From f7d3c48b2559318c1b0f2cede80bb00630ac8579 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 05:27:45 +0200 Subject: [PATCH 372/433] * Disable Facebook / Twitter button for 0.5 release. Renamed OK to Share. --- src/SocialWidget.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index 09cad1014..c05c2a497 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -55,7 +55,9 @@ SocialWidget::SocialWidget( QWidget* parent ) #endif ui->charsLeftLabel->setForegroundRole( QPalette::HighlightedText ); - + + ui->buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Share" ) ); + m_parent->installEventFilter( this ); connect( ui->buttonBox, SIGNAL( accepted() ), SLOT( accept() ) ); @@ -66,6 +68,10 @@ SocialWidget::SocialWidget( QWidget* parent ) connect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ), SLOT( onShortLinkReady( QUrl, QUrl, QVariant ) ) ); onChanged(); + + ui->twitterButton->setChecked( true ); + ui->twitterButton->setVisible( false ); + ui->facebookButton->setVisible( false ); } From 35a25c3971d4a7dabb80874b4bd24bc76f3c45ad Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 05:41:19 +0200 Subject: [PATCH 373/433] * Don't track history for destroyed widgets. --- src/libtomahawk/ViewManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 445eea592..92d594e07 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -871,6 +871,7 @@ ViewManager::onWidgetDestroyed( QWidget* widget ) if ( resetWidget ) { + m_currentPage = 0; historyBack(); } } From 4acf96429e039ce632de4ada7c7757573d86b5ff Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 07:41:43 +0200 Subject: [PATCH 374/433] * Added jump-link.png to resources. --- resources.qrc | 1 + 1 file changed, 1 insertion(+) diff --git a/resources.qrc b/resources.qrc index 05f94a4b9..c45c6e1f1 100644 --- a/resources.qrc +++ b/resources.qrc @@ -143,5 +143,6 @@ data/images/collection.png data/misc/tomahawk_pubkey.pem data/images/track-icon-sidebar.png + data/images/jump-link.png From aeeaaadcd27b64310a63ff8379c77237778cf18f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 07:42:02 +0200 Subject: [PATCH 375/433] * Reimplemented ViewManager::pageForInterface. --- src/libtomahawk/ViewManager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 92d594e07..f7b198ba3 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -936,14 +936,16 @@ ViewManager::pageForPlaylist(const playlist_ptr& pl) const ViewPage* ViewManager::pageForInterface( Tomahawk::playlistinterface_ptr interface ) const { -/* for ( int i = 0; i < m_pageHistory.count(); i++ ) + QList< Tomahawk::ViewPage* > pages = historyPages(); + + for ( int i = 0; i < pages.count(); i++ ) { - ViewPage* page = m_pageHistory.at( i ); + ViewPage* page = pages.at( i ); if ( page->playlistInterface() == interface ) return page; if ( page->playlistInterface() && page->playlistInterface()->hasChildInterface( interface ) ) return page; - }*/ + } return 0; } From fa4ef44e4af7abee4435dabe2261fe7e3331e2cb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 07:45:14 +0200 Subject: [PATCH 376/433] * QueryLabel now supports displaying a jump-label and handles cursor states itself. --- src/libtomahawk/widgets/QueryLabel.cpp | 34 ++++++++++++++++++++++++++ src/libtomahawk/widgets/QueryLabel.h | 5 ++++ 2 files changed, 39 insertions(+) diff --git a/src/libtomahawk/widgets/QueryLabel.cpp b/src/libtomahawk/widgets/QueryLabel.cpp index 82b40d084..017e9b3f2 100644 --- a/src/libtomahawk/widgets/QueryLabel.cpp +++ b/src/libtomahawk/widgets/QueryLabel.cpp @@ -30,6 +30,7 @@ #include "ContextMenu.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" +#include "ViewManager.h" #include "Source.h" #define BOXMARGIN 2 @@ -91,6 +92,9 @@ QueryLabel::init() m_useCustomFont = false; m_align = Qt::AlignLeft | Qt::AlignVCenter; m_mode = Qt::ElideMiddle; + + m_jumpLinkVisible = false; + m_jumpPixmap = QPixmap( RESPATH "images/jump-link.png" ).scaled( QSize( fontMetrics().height(), fontMetrics().height() ), Qt::KeepAspectRatio, Qt::SmoothTransformation ); } @@ -240,6 +244,14 @@ QueryLabel::setQuery( const Tomahawk::query_ptr& query ) } +void +QueryLabel::setJumpLinkVisible( bool visible ) +{ + m_jumpLinkVisible = visible; + repaint(); +} + + Qt::Alignment QueryLabel::alignment() const { @@ -466,6 +478,13 @@ QueryLabel::paintEvent( QPaintEvent* event ) p.drawText( r, m_align, track() ); r.adjust( trackX, 0, 0, 0 ); } + + if ( m_jumpLinkVisible ) + { + r.adjust( 6, 0, 0, 0 ); + r.setSize( m_jumpPixmap.size() ); + p.drawPixmap( r, m_jumpPixmap ); + } } p.restore(); @@ -527,6 +546,10 @@ QueryLabel::mouseReleaseEvent( QMouseEvent* event ) case Track: emit clickedTrack(); break; + + case Complete: + ViewManager::instance()->showCurrentTrack(); + break; default: emit clicked(); @@ -583,6 +606,7 @@ QueryLabel::mouseMoveEvent( QMouseEvent* event ) QRect hoverArea; m_hoverType = None; + if ( m_type & Artist && x < artistX ) { m_hoverType = Artist; @@ -603,12 +627,22 @@ QueryLabel::mouseMoveEvent( QMouseEvent* event ) hoverArea.setLeft( albumX + spacing ); hoverArea.setRight( trackX + contentsMargins().left() - 1 ); } + else if ( m_jumpLinkVisible && x < trackX + 6 + m_jumpPixmap.width() && x > trackX + 6 ) + { + m_hoverType = Complete; + } if ( hoverArea.width() ) { hoverArea.setY( 1 ); hoverArea.setHeight( height() - 2 ); } + + if ( m_hoverType != None ) + setCursor( Qt::PointingHandCursor ); + else + setCursor( Qt::ArrowCursor ); + if ( hoverArea != m_hoverArea ) { m_hoverArea = hoverArea; diff --git a/src/libtomahawk/widgets/QueryLabel.h b/src/libtomahawk/widgets/QueryLabel.h index f9d655dd4..3667a2c9e 100644 --- a/src/libtomahawk/widgets/QueryLabel.h +++ b/src/libtomahawk/widgets/QueryLabel.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "Result.h" #include "Query.h" @@ -80,6 +81,7 @@ public: QFont font() const; void setExtraContentsMargins( int left, int top, int right, int bottom ); + void setJumpLinkVisible( bool visible ); virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; @@ -137,6 +139,9 @@ private: QRect m_hoverArea; QPoint m_dragPos; QMargins m_textMargins; + + bool m_jumpLinkVisible; + QPixmap m_jumpPixmap; }; #endif // QUERYLABEL_H From 6a8edd688bc7173918625abd5890ebd10f03e52b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 07:45:40 +0200 Subject: [PATCH 377/433] * Use jump-label in AudioControls. --- src/AudioControls.cpp | 2 +- src/AudioControls.ui | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 43c2cb1a0..99d177c73 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -61,6 +61,7 @@ AudioControls::AudioControls( QWidget* parent ) ui->artistTrackLabel->setFont( font ); ui->artistTrackLabel->setElideMode( Qt::ElideMiddle ); ui->artistTrackLabel->setType( QueryLabel::ArtistAndTrack ); + ui->artistTrackLabel->setJumpLinkVisible( true ); ui->albumLabel->setFont( font ); ui->albumLabel->setType( QueryLabel::Album ); @@ -549,7 +550,6 @@ void AudioControls::onTrackClicked() { ViewManager::instance()->show( m_currentTrack->toQuery() ); -// ViewManager::instance()->showCurrentTrack(); } diff --git a/src/AudioControls.ui b/src/AudioControls.ui index d8db84968..2ce80c3f8 100644 --- a/src/AudioControls.ui +++ b/src/AudioControls.ui @@ -207,9 +207,6 @@ 16 - - PointingHandCursor - Artist @@ -229,9 +226,6 @@ 16 - - PointingHandCursor - Album From 82febe8da396e999e30e0db3ce3851e2ee6b389b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 07:48:04 +0200 Subject: [PATCH 378/433] * Hardcode foreground color for OverlayWidgets. Needs improved color management eventually. --- src/libtomahawk/widgets/OverlayWidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/widgets/OverlayWidget.cpp b/src/libtomahawk/widgets/OverlayWidget.cpp index d3e896d64..a72066f23 100644 --- a/src/libtomahawk/widgets/OverlayWidget.cpp +++ b/src/libtomahawk/widgets/OverlayWidget.cpp @@ -248,6 +248,7 @@ OverlayWidget::paintEvent( QPaintEvent* event ) } p.setFont( f ); - p.setPen( palette().highlightedText().color() ); +// p.setPen( palette().highlightedText().color() ); + p.setPen( Qt::white ); p.drawText( r.adjusted( 8, 8, -8, -8 ), text(), to ); } From d0a8f2d1b9f57d443de3ad82f8be2be5c27324d8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 08:41:10 +0200 Subject: [PATCH 379/433] * Safer cover loading for Artists & Albums. --- src/libtomahawk/Album.cpp | 5 +++-- src/libtomahawk/Artist.cpp | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/Album.cpp b/src/libtomahawk/Album.cpp index 909f17fe2..5fa1ae290 100644 --- a/src/libtomahawk/Album.cpp +++ b/src/libtomahawk/Album.cpp @@ -181,7 +181,7 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, if ( ba.length() ) { m_coverBuffer = ba; - + m_coverLoaded = true; emit coverChanged(); } } @@ -200,7 +200,8 @@ Album::infoSystemFinished( const QString& target ) disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), this, SLOT( infoSystemFinished( QString ) ) ); - m_coverLoaded = true; + m_coverLoading = false; + emit updated(); } diff --git a/src/libtomahawk/Artist.cpp b/src/libtomahawk/Artist.cpp index ba44cda76..f06a542bb 100644 --- a/src/libtomahawk/Artist.cpp +++ b/src/libtomahawk/Artist.cpp @@ -382,6 +382,8 @@ Artist::infoSystemFinished( QString target ) this, SLOT( infoSystemFinished( QString ) ) ); } + m_coverLoading = false; + emit updated(); } From b3ebcb59c006f61ef0485b3a202caf3932697466 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 08:58:40 +0200 Subject: [PATCH 380/433] * Only try loading covers once. --- src/libtomahawk/Album.cpp | 3 ++- src/libtomahawk/Artist.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/Album.cpp b/src/libtomahawk/Album.cpp index 5fa1ae290..a639042c7 100644 --- a/src/libtomahawk/Album.cpp +++ b/src/libtomahawk/Album.cpp @@ -181,9 +181,10 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, if ( ba.length() ) { m_coverBuffer = ba; - m_coverLoaded = true; emit coverChanged(); } + + m_coverLoaded = true; } } diff --git a/src/libtomahawk/Artist.cpp b/src/libtomahawk/Artist.cpp index f06a542bb..fbd30f477 100644 --- a/src/libtomahawk/Artist.cpp +++ b/src/libtomahawk/Artist.cpp @@ -321,9 +321,10 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari if ( ba.length() ) { m_coverBuffer = ba; - m_coverLoaded = true; emit coverChanged(); } + + m_coverLoaded = true; } break; From f2503afd6959a81d60d72c7ad44862c958da8067 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 12 Jun 2012 09:14:31 +0200 Subject: [PATCH 381/433] Try letting NSString live longer --- src/libtomahawk/mac/FileHelpers.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/mac/FileHelpers.mm b/src/libtomahawk/mac/FileHelpers.mm index b8a0f0cce..ef7573761 100644 --- a/src/libtomahawk/mac/FileHelpers.mm +++ b/src/libtomahawk/mac/FileHelpers.mm @@ -203,8 +203,9 @@ static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authoriza NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:success], TKInstallerResultKey, [info objectForKey:TKInstallerDelegateKey], TKInstallerDelegateKey, error, TKInstallerErrorKey, nil]; [self notifyDelegate:dict]; + // TODO Do not release yet as seems to crash on some systems. // [fromPath release]; - [toPath release]; +// [toPath release]; } From 8cf7f0bb2bcda24938b0bd3b613210bfb09fcfd0 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 09:31:09 +0200 Subject: [PATCH 382/433] * Make sure m_defaultImage is properly init'ed. --- src/libtomahawk/utils/PixmapDelegateFader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/utils/PixmapDelegateFader.cpp b/src/libtomahawk/utils/PixmapDelegateFader.cpp index b03e57f6d..b1f2bfa56 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.cpp +++ b/src/libtomahawk/utils/PixmapDelegateFader.cpp @@ -100,6 +100,8 @@ PixmapDelegateFader::init() { if ( m_currentReference.isNull() ) m_defaultImage = true; + else + m_defaultImage = false; m_startFrame = 0; m_fadePct = 100; From ecc8634209b87d274cc8a0383097c082d2a1a6fb Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 12 Jun 2012 09:39:17 +0200 Subject: [PATCH 383/433] Only remove from pipeline on destruction if still running --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index b99a8e3cf..1bfa4ea5e 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -231,7 +231,9 @@ QtScriptResolver::QtScriptResolver( const QString& scriptPath ) QtScriptResolver::~QtScriptResolver() { - Tomahawk::Pipeline::instance()->removeResolver( this ); + if ( !m_stopped ) + stop(); + delete m_engine; } From e72062b05c8565d211c409b00a20f3a8fcf0c837 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Tue, 12 Jun 2012 10:03:40 -0400 Subject: [PATCH 384/433] Removed LOVING IT from tweet text since you didn't actually love it, and changed SHARE button text to TWEET for now until we get Facebook back in --- src/SocialWidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index c05c2a497..65aa651fe 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -56,7 +56,7 @@ SocialWidget::SocialWidget( QWidget* parent ) ui->charsLeftLabel->setForegroundRole( QPalette::HighlightedText ); - ui->buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Share" ) ); + ui->buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Tweet" ) ); m_parent->installEventFilter( this ); @@ -203,9 +203,9 @@ SocialWidget::onShortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const Q_UNUSED( callbackObj ); if ( m_query->album().isEmpty() ) - ui->textEdit->setText( tr( "Listening to \"%1\" by %2 and loving it! %3" ).arg( m_query->track() ).arg( m_query->artist() ).arg( shortUrl.toString() ) ); + ui->textEdit->setText( tr( "Listening to \"%1\" by %2. %3" ).arg( m_query->track() ).arg( m_query->artist() ).arg( shortUrl.toString() ) ); else - ui->textEdit->setText( tr( "Listening to \"%1\" by %2 on \"%3\" and loving it! %4" ).arg( m_query->track() ).arg( m_query->artist() ).arg( m_query->album() ).arg( shortUrl.toString() ) ); + ui->textEdit->setText( tr( "Listening to \"%1\" by %2 on \"%3\". %4" ).arg( m_query->track() ).arg( m_query->artist() ).arg( m_query->album() ).arg( shortUrl.toString() ) ); } From 3456f5d03882248064f737678a46a1ae22f6bd39 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 12 Jun 2012 17:13:37 +0200 Subject: [PATCH 385/433] Mark liblastfm as required --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12535f17c..6cb29dfeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,7 +134,7 @@ macro_optional_find_package(QTweetLib) macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin.\n") macro_optional_find_package(LibLastFm 1.0.0) -macro_log_feature(LIBLASTFM_FOUND "liblastfm" "Qt library for the Last.fm webservices" "https://github.com/eartle/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") +macro_log_feature(LIBLASTFM_FOUND "liblastfm" "Qt library for the Last.fm webservices" "https://github.com/eartle/liblastfm" TRUE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") #### submodules start # automatically init submodules here, don't delete this code we may add submodules again From 833a9f59d3b7b6317b1a4d36f613a2369770aae3 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 12 Jun 2012 17:28:58 +0200 Subject: [PATCH 386/433] Don't crash when moving the mouse after hitting Cancel in the Share widget --- src/SocialWidget.cpp | 11 ++++++++++- src/SocialWidget.h | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index 65aa651fe..a1b6a978b 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -61,7 +61,7 @@ SocialWidget::SocialWidget( QWidget* parent ) m_parent->installEventFilter( this ); connect( ui->buttonBox, SIGNAL( accepted() ), SLOT( accept() ) ); - connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( deleteLater() ) ); + connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( close() ) ); connect( ui->textEdit, SIGNAL( textChanged() ), SLOT( onChanged() ) ); connect( ui->facebookButton, SIGNAL( clicked( bool ) ), SLOT( onChanged() ) ); connect( ui->twitterButton, SIGNAL( clicked( bool ) ), SLOT( onChanged() ) ); @@ -89,6 +89,7 @@ SocialWidget::setOpacity( qreal opacity ) if ( m_opacity == 0.00 && !isHidden() ) { QWidget::hide(); + emit hidden(); } else if ( m_opacity > 0.00 && isHidden() ) { @@ -254,6 +255,14 @@ SocialWidget::accept() } +void +SocialWidget::close() +{ + hide(); + connect( this, SIGNAL( hidden() ), this, SLOT( deleteLater() ) ); +} + + unsigned int SocialWidget::charsAvailable() const { diff --git a/src/SocialWidget.h b/src/SocialWidget.h index 0fddf9a54..ec4230d5b 100644 --- a/src/SocialWidget.h +++ b/src/SocialWidget.h @@ -50,6 +50,9 @@ public: bool shown() const; +signals: + void hidden(); + public slots: void show( int timeoutSecs = 0 ); void hide(); @@ -65,6 +68,7 @@ private slots: void onShortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const QVariant& callbackObj ); void onGeometryUpdate(); + void close(); private: unsigned int charsAvailable() const; From bcd7d826547d81581693fca9e562cd0ab5799c9f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 19:46:24 +0200 Subject: [PATCH 387/433] * Missing breaks. --- src/libtomahawk/audio/AudioEngine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index 773adbb6d..75266df98 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -860,12 +860,15 @@ AudioEngine::checkStateQueue() m_mediaObject->play(); if ( paused ) setVolume( m_volume ); + + break; } case Paused: { m_volume = volume(); m_mediaObject->pause(); + break; } } } From a00c931192df2168c324f1898282442e24545e72 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 21:17:39 +0200 Subject: [PATCH 388/433] * Make SocialWidget less transparent. --- src/SocialWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index a1b6a978b..d14414017 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -30,7 +30,7 @@ #define CORNER_ROUNDNESS 8.0 #define FADING_DURATION 500 #define FONT_SIZE 16 -#define OPACITY 0.70 +#define OPACITY 0.85 SocialWidget::SocialWidget( QWidget* parent ) From 14d7b882fa655d529c1ab37fc52c72e21c348441 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 12 Jun 2012 21:27:00 +0200 Subject: [PATCH 389/433] * Don't fade out SocialWidget. --- src/SocialWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SocialWidget.cpp b/src/SocialWidget.cpp index d14414017..9f0536f90 100644 --- a/src/SocialWidget.cpp +++ b/src/SocialWidget.cpp @@ -258,8 +258,8 @@ SocialWidget::accept() void SocialWidget::close() { - hide(); - connect( this, SIGNAL( hidden() ), this, SLOT( deleteLater() ) ); + QWidget::hide(); + deleteLater(); } From 8401befe6b30674721518ef18cc17cc03cd2908d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= Date: Tue, 12 Jun 2012 23:04:33 +0200 Subject: [PATCH 390/433] Enable Subscribing on SpotifyPlaylists --- .../accounts/spotify/SpotifyAccount.cpp | 124 ++++++++++++++++-- .../accounts/spotify/SpotifyAccount.h | 31 +++-- .../spotify/SpotifyPlaylistUpdater.cpp | 23 +++- .../accounts/spotify/SpotifyPlaylistUpdater.h | 5 + src/libtomahawk/utils/SpotifyParser.cpp | 15 +++ src/libtomahawk/utils/SpotifyParser.h | 4 +- 6 files changed, 179 insertions(+), 23 deletions(-) diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index d786be550..0b79e985d 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -47,6 +47,7 @@ using namespace Accounts; static QPixmap* s_icon = 0; +SpotifyAccount* SpotifyAccount::s_instance = 0; #ifdef Q_OS_MAC static QString s_resolverId = "spotify-osx"; @@ -81,10 +82,10 @@ SpotifyAccount::SpotifyAccount( const QString& accountId ) : CustomAtticaAccount( accountId ) , m_preventEnabling( false ) { + s_instance = this; init(); } - SpotifyAccount::~SpotifyAccount() { clearUser(); @@ -346,9 +347,12 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) if ( !m_customActions.contains( action ) ) return; + // If it's not being synced, allow the option to sync bool found = false; bool manuallyDisabled = false; + bool canSubscribe = false; + bool isSubscribed = false; QList updaters = playlist->updaters(); foreach ( PlaylistUpdaterInterface* updater, updaters ) { @@ -358,21 +362,42 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) if ( !spotifyUpdater->sync() ) manuallyDisabled = true; + canSubscribe = spotifyUpdater->canSubscribe(); + isSubscribed = spotifyUpdater->subscribed(); + qDebug() << "canSub " << canSubscribe << " is Sub " << isSubscribed << "isSibb " << spotifyUpdater->subscribed(); } } if ( !found ) { action->setText( tr( "Sync with Spotify" ) ); + action->setProperty( "type", Sync ); } - else if ( manuallyDisabled ) + + else if ( manuallyDisabled && !canSubscribe ) { action->setText( tr( "Re-enable syncing with Spotify" ) ); + action->setProperty( "type", Sync ); + } + else if ( canSubscribe && !isSubscribed ) + { + action->setText( tr( "Subscribe with Spotify" ) ); + action->setProperty( "type", Subscribe ); } else { - action->setText( tr( "Stop syncing with Spotify" ) ); + if ( canSubscribe ) + { + action->setText( tr( "Stop Subscribing with Spotify" ) ); + action->setProperty( "type", UnSubscribe); + } + else + { + action->setText( tr( "Stop syncing with Spotify" ) ); + action->setProperty( "type", UnSync); + } } + } @@ -431,21 +456,95 @@ SpotifyAccount::syncActionTriggered( bool checked ) } } - Q_ASSERT( info ); if ( info ) + { + qDebug() << "Found info!"; info->sync = !updater->sync(); + info->subscribe = !updater->sync(); + } + else if( action->property("type").toInt() == Subscribe | UnSubscribe ) + { + qDebug() << "ADDING PLAYLIST INFO!"; + info = new SpotifyPlaylistInfo( playlist->title(), updater->spotifyId(), updater->spotifyId(), true, false ); + } + + Q_ASSERT( info ); if ( m_configWidget.data() ) m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists ); - if ( !updater->sync() ) + + switch( action->property("type").toInt() ) { - startPlaylistSync( info ); - } - else - { - stopPlaylistSync( info, true ); + case Sync: + startPlaylistSync( info ); + break; + case UnSync: + stopPlaylistSync( info, true ); + break; + case Subscribe: + qDebug() << "Got subscribe!"; + startPlaylistSubscribe( info ); + break; + case UnSubscribe: + qDebug() << "Got UNsubscribe!"; + stopPlaylistSubscribe( info ); + break; + default: + qDebug() << "I DONNO WHAT TO DO"; + break; + } + + + } +} + + +void +SpotifyAccount::stopPlaylistSubscribe( SpotifyPlaylistInfo* playlist ) +{ + + qDebug() << Q_FUNC_INFO; + + if ( !playlist ) + return; + + QVariantMap msg; + msg[ "_msgtype" ] = "setSubscription"; + msg[ "playlistid" ] = playlist->plid; + msg[ "subscribed" ] = false; + + sendMessage( msg, 0, "setSubscription" ); + + if ( m_updaters.contains( playlist->plid ) ) + { + SpotifyPlaylistUpdater* updater = m_updaters[ playlist->plid ]; + updater->setSubscribe( false ); + updater->save(); + } +} + +void +SpotifyAccount::startPlaylistSubscribe( SpotifyPlaylistInfo* playlist ) +{ + qDebug() << Q_FUNC_INFO; + + if ( !playlist ) + return; + + QVariantMap msg; + msg[ "_msgtype" ] = "setSubscription"; + msg[ "playlistid" ] = playlist->plid; + msg[ "subscribed" ] = true; + + sendMessage( msg, 0, "setSubscription" ); + + if ( m_updaters.contains( playlist->plid ) ) + { + SpotifyPlaylistUpdater* updater = m_updaters[ playlist->plid ]; + updater->setSubscribe( true ); + updater->save(); } } @@ -495,13 +594,13 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg const QString plid = plMap.value( "id" ).toString(); const QString revid = plMap.value( "revid" ).toString(); const bool sync = plMap.value( "sync" ).toBool(); - + const bool subscribe = plMap.value( "subscribe" ).toBool(); if ( name.isNull() || plid.isNull() || revid.isNull() ) { qDebug() << "Did not get name and plid and revid for spotify playlist:" << name << plid << revid << plMap; continue; } - m_allSpotifyPlaylists << new SpotifyPlaylistInfo( name, plid, revid, sync ); + m_allSpotifyPlaylists << new SpotifyPlaylistInfo( name, plid, revid, sync, subscribe ); } if ( !m_configWidget.isNull() ) @@ -796,7 +895,6 @@ SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist ) sendMessage( msg, this, "startPlaylistSyncWithPlaylist" ); } - void SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg ) { diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h index f31d97309..05ca87787 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -42,13 +42,13 @@ class SpotifyAccountConfig; // metadata for a playlist struct SpotifyPlaylistInfo { QString name, plid, revid; - bool sync, changed; + bool sync, changed, subscribe; - SpotifyPlaylistInfo( const QString& nname, const QString& pid, const QString& rrevid, bool ssync ) - : name( nname ), plid( pid ), revid( rrevid ), sync( ssync ), changed( false ) {} + SpotifyPlaylistInfo( const QString& nname, const QString& pid, const QString& rrevid, bool ssync, bool ssubscribe ) + : name( nname ), plid( pid ), revid( rrevid ), sync( ssync ), changed( false ), subscribe( ssubscribe ) {} - SpotifyPlaylistInfo() : sync( false ), changed( false ) {} + SpotifyPlaylistInfo() : sync( false ), changed( false ), subscribe( false ) {} }; @@ -78,6 +78,10 @@ public: SpotifyAccount( const QString& accountId, const QString& path ); virtual ~SpotifyAccount(); + static SpotifyAccount* instance() { + return s_instance; + } + virtual QPixmap icon() const; virtual QWidget* configurationWidget(); virtual QWidget* aboutWidget(); @@ -94,12 +98,9 @@ public: virtual bool preventEnabling() const { return m_preventEnabling; } QString sendMessage( const QVariantMap& msg, QObject* receiver = 0, const QString& slot = QString() ); - void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater ); void unregisterUpdater( const QString& plid ); - bool deleteOnUnsync() const; - void setManualResolverPath( const QString& resolverPath ); public slots: @@ -133,9 +134,21 @@ private: void startPlaylistSync( SpotifyPlaylistInfo* playlist ); void stopPlaylistSync( SpotifyPlaylistInfo* playlist, bool forceDontDelete = false ); void fetchFullPlaylist( SpotifyPlaylistInfo* playlist ); - void setSyncForPlaylist( const QString& spotifyPlaylistId, bool sync ); + void stopPlaylistSubscribe( SpotifyPlaylistInfo* playlist ); + void startPlaylistSubscribe( SpotifyPlaylistInfo* playlist ); + + enum Actions{ + + None = 0x01, + Subscribe = 0x02, + Sync = 0x04, + UnSubscribe = 0x06, + UnSync = 0x08 + }; + + Actions m_action; void createActions(); void removeActions(); @@ -155,6 +168,8 @@ private: SmartPointerList< QAction > m_customActions; friend class ::SpotifyPlaylistUpdater; + + static SpotifyAccount* s_instance; }; } diff --git a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp index 64bdda98f..ec544b89b 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp @@ -74,6 +74,7 @@ SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const QStr , m_spotifyId( spotifyId ) , m_blockUpdatesForNextRevision( false ) , m_sync( false ) + , m_subscribe( false ) { init(); } @@ -194,13 +195,14 @@ SpotifyPlaylistUpdater::type() const QPixmap SpotifyPlaylistUpdater::typeIcon() const { + if ( !s_typePixmap ) { QPixmap pm( RESPATH "images/spotify-logo.png" ); s_typePixmap = new QPixmap( pm.scaled( 32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); } - if ( !m_sync ) + if( !m_sync ) return QPixmap(); return *s_typePixmap; @@ -220,6 +222,17 @@ SpotifyPlaylistUpdater::setSync( bool sync ) emit changed(); } +void +SpotifyPlaylistUpdater::setSubscribe( bool sub ) +{ + if ( m_subscribe == sub ) + return; + + m_subscribe = sub; + + saveToSettings(); + emit changed(); +} bool SpotifyPlaylistUpdater::sync() const @@ -227,6 +240,14 @@ SpotifyPlaylistUpdater::sync() const return m_sync; } +bool +SpotifyPlaylistUpdater::canSubscribe() +{ + + qDebug() << " canSubscribe " << m_spotify.data()->credentials().value( "username" ).toString() << m_spotifyId; + return !m_spotifyId.contains( m_spotify.data()->credentials().value( "username" ).toString() ); + +} void SpotifyPlaylistUpdater::spotifyTracksAdded( const QVariantList& tracks, const QString& startPosId, const QString& newRev, const QString& oldRev ) diff --git a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h index 896e507d3..cabfb68b5 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h +++ b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h @@ -53,6 +53,9 @@ public: bool sync() const; void setSync( bool sync ); + bool canSubscribe(); + void setSubscribe( bool sub ); + bool subscribed() { return m_subscribe; } QString spotifyId() const { return m_spotifyId; } @@ -99,6 +102,8 @@ private: bool m_blockUpdatesForNextRevision; bool m_sync; + bool m_subscribe; + bool m_canSubscribe; QQueue<_detail::Closure*> m_queuedOps; #ifndef ENABLE_HEADLESS diff --git a/src/libtomahawk/utils/SpotifyParser.cpp b/src/libtomahawk/utils/SpotifyParser.cpp index b03276412..0e968b190 100644 --- a/src/libtomahawk/utils/SpotifyParser.cpp +++ b/src/libtomahawk/utils/SpotifyParser.cpp @@ -116,6 +116,7 @@ SpotifyParser::lookupSpotifyBrowse( const QString& linkRaw ) type = DropJob::Track; QUrl url; + m_browseId = browseUri; if( type != DropJob::Artist ) url = QUrl( QString( SPOTIFY_PLAYLIST_API_URL "/browse/%1" ).arg( browseUri ) ); @@ -302,6 +303,8 @@ SpotifyParser::checkBrowseFinished() if( m_createNewPlaylist && !m_tracks.isEmpty() ) { + + m_playlist = Playlist::create( SourceList::instance()->getLocal(), uuid(), m_title, @@ -309,6 +312,18 @@ SpotifyParser::checkBrowseFinished() m_creator, false, m_tracks ); + + if( Tomahawk::Accounts::SpotifyAccount::instance() != 0 ) + { + + qDebug() << "FOUND SPOTIFY ACCOUNT!!" << Tomahawk::Accounts::SpotifyAccount::instance()->credentials().value("username") << Tomahawk::Accounts::SpotifyAccount::instance()->isAuthenticated(); + SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount::instance(), m_browseId, m_browseId, m_playlist ); + updater->setSync( true ); + updater->setSubscribe( false ); + Tomahawk::Accounts::SpotifyAccount::instance()->registerUpdaterForPlaylist( m_browseId, updater); + + } + connect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistCreated() ) ); return; } diff --git a/src/libtomahawk/utils/SpotifyParser.h b/src/libtomahawk/utils/SpotifyParser.h index 7f5c65b61..0cc5ea23e 100644 --- a/src/libtomahawk/utils/SpotifyParser.h +++ b/src/libtomahawk/utils/SpotifyParser.h @@ -28,6 +28,8 @@ #include #include #include +#include "accounts/spotify/SpotifyAccount.h" +#include "accounts/spotify/SpotifyPlaylistUpdater.h" #define SPOTIFY_PLAYLIST_API_URL "http://spotikea.tomahawk-player.org" @@ -84,7 +86,7 @@ private: QString m_title, m_info, m_creator; Tomahawk::playlist_ptr m_playlist; DropJobNotifier* m_browseJob; - + QString m_browseId; static QPixmap* s_pixmap; }; From d18439b4ae0e692a4f010b4aaf911895f0cdf6d4 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 12 Jun 2012 23:26:13 +0200 Subject: [PATCH 391/433] Revert "Enable Subscribing on SpotifyPlaylists" Looks fine but holding off until post-0.5.0 is tagged as I would like to test it quite thoroughly :) This reverts commit 8401befe6b30674721518ef18cc17cc03cd2908d. --- .../accounts/spotify/SpotifyAccount.cpp | 126 ++---------------- .../accounts/spotify/SpotifyAccount.h | 31 ++--- .../spotify/SpotifyPlaylistUpdater.cpp | 23 +--- .../accounts/spotify/SpotifyPlaylistUpdater.h | 5 - src/libtomahawk/utils/SpotifyParser.cpp | 15 --- src/libtomahawk/utils/SpotifyParser.h | 4 +- 6 files changed, 24 insertions(+), 180 deletions(-) diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index 0b79e985d..d786be550 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -47,7 +47,6 @@ using namespace Accounts; static QPixmap* s_icon = 0; -SpotifyAccount* SpotifyAccount::s_instance = 0; #ifdef Q_OS_MAC static QString s_resolverId = "spotify-osx"; @@ -82,10 +81,10 @@ SpotifyAccount::SpotifyAccount( const QString& accountId ) : CustomAtticaAccount( accountId ) , m_preventEnabling( false ) { - s_instance = this; init(); } + SpotifyAccount::~SpotifyAccount() { clearUser(); @@ -347,12 +346,9 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) if ( !m_customActions.contains( action ) ) return; - // If it's not being synced, allow the option to sync bool found = false; bool manuallyDisabled = false; - bool canSubscribe = false; - bool isSubscribed = false; QList updaters = playlist->updaters(); foreach ( PlaylistUpdaterInterface* updater, updaters ) { @@ -362,42 +358,21 @@ SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist ) if ( !spotifyUpdater->sync() ) manuallyDisabled = true; - canSubscribe = spotifyUpdater->canSubscribe(); - isSubscribed = spotifyUpdater->subscribed(); - qDebug() << "canSub " << canSubscribe << " is Sub " << isSubscribed << "isSibb " << spotifyUpdater->subscribed(); } } if ( !found ) { action->setText( tr( "Sync with Spotify" ) ); - action->setProperty( "type", Sync ); } - - else if ( manuallyDisabled && !canSubscribe ) + else if ( manuallyDisabled ) { action->setText( tr( "Re-enable syncing with Spotify" ) ); - action->setProperty( "type", Sync ); - } - else if ( canSubscribe && !isSubscribed ) - { - action->setText( tr( "Subscribe with Spotify" ) ); - action->setProperty( "type", Subscribe ); } else { - if ( canSubscribe ) - { - action->setText( tr( "Stop Subscribing with Spotify" ) ); - action->setProperty( "type", UnSubscribe); - } - else - { - action->setText( tr( "Stop syncing with Spotify" ) ); - action->setProperty( "type", UnSync); - } + action->setText( tr( "Stop syncing with Spotify" ) ); } - } @@ -456,95 +431,21 @@ SpotifyAccount::syncActionTriggered( bool checked ) } } - if ( info ) - { - qDebug() << "Found info!"; - info->sync = !updater->sync(); - info->subscribe = !updater->sync(); - } - else if( action->property("type").toInt() == Subscribe | UnSubscribe ) - { - qDebug() << "ADDING PLAYLIST INFO!"; - info = new SpotifyPlaylistInfo( playlist->title(), updater->spotifyId(), updater->spotifyId(), true, false ); - } - Q_ASSERT( info ); + if ( info ) + info->sync = !updater->sync(); if ( m_configWidget.data() ) m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists ); - - switch( action->property("type").toInt() ) + if ( !updater->sync() ) { - case Sync: - startPlaylistSync( info ); - break; - case UnSync: - stopPlaylistSync( info, true ); - break; - case Subscribe: - qDebug() << "Got subscribe!"; - startPlaylistSubscribe( info ); - break; - case UnSubscribe: - qDebug() << "Got UNsubscribe!"; - stopPlaylistSubscribe( info ); - break; - default: - qDebug() << "I DONNO WHAT TO DO"; - break; - + startPlaylistSync( info ); + } + else + { + stopPlaylistSync( info, true ); } - - - } -} - - -void -SpotifyAccount::stopPlaylistSubscribe( SpotifyPlaylistInfo* playlist ) -{ - - qDebug() << Q_FUNC_INFO; - - if ( !playlist ) - return; - - QVariantMap msg; - msg[ "_msgtype" ] = "setSubscription"; - msg[ "playlistid" ] = playlist->plid; - msg[ "subscribed" ] = false; - - sendMessage( msg, 0, "setSubscription" ); - - if ( m_updaters.contains( playlist->plid ) ) - { - SpotifyPlaylistUpdater* updater = m_updaters[ playlist->plid ]; - updater->setSubscribe( false ); - updater->save(); - } -} - -void -SpotifyAccount::startPlaylistSubscribe( SpotifyPlaylistInfo* playlist ) -{ - qDebug() << Q_FUNC_INFO; - - if ( !playlist ) - return; - - QVariantMap msg; - msg[ "_msgtype" ] = "setSubscription"; - msg[ "playlistid" ] = playlist->plid; - msg[ "subscribed" ] = true; - - sendMessage( msg, 0, "setSubscription" ); - - if ( m_updaters.contains( playlist->plid ) ) - { - SpotifyPlaylistUpdater* updater = m_updaters[ playlist->plid ]; - updater->setSubscribe( true ); - updater->save(); } } @@ -594,13 +495,13 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg const QString plid = plMap.value( "id" ).toString(); const QString revid = plMap.value( "revid" ).toString(); const bool sync = plMap.value( "sync" ).toBool(); - const bool subscribe = plMap.value( "subscribe" ).toBool(); + if ( name.isNull() || plid.isNull() || revid.isNull() ) { qDebug() << "Did not get name and plid and revid for spotify playlist:" << name << plid << revid << plMap; continue; } - m_allSpotifyPlaylists << new SpotifyPlaylistInfo( name, plid, revid, sync, subscribe ); + m_allSpotifyPlaylists << new SpotifyPlaylistInfo( name, plid, revid, sync ); } if ( !m_configWidget.isNull() ) @@ -895,6 +796,7 @@ SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist ) sendMessage( msg, this, "startPlaylistSyncWithPlaylist" ); } + void SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg ) { diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h index 05ca87787..f31d97309 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -42,13 +42,13 @@ class SpotifyAccountConfig; // metadata for a playlist struct SpotifyPlaylistInfo { QString name, plid, revid; - bool sync, changed, subscribe; + bool sync, changed; - SpotifyPlaylistInfo( const QString& nname, const QString& pid, const QString& rrevid, bool ssync, bool ssubscribe ) - : name( nname ), plid( pid ), revid( rrevid ), sync( ssync ), changed( false ), subscribe( ssubscribe ) {} + SpotifyPlaylistInfo( const QString& nname, const QString& pid, const QString& rrevid, bool ssync ) + : name( nname ), plid( pid ), revid( rrevid ), sync( ssync ), changed( false ) {} - SpotifyPlaylistInfo() : sync( false ), changed( false ), subscribe( false ) {} + SpotifyPlaylistInfo() : sync( false ), changed( false ) {} }; @@ -78,10 +78,6 @@ public: SpotifyAccount( const QString& accountId, const QString& path ); virtual ~SpotifyAccount(); - static SpotifyAccount* instance() { - return s_instance; - } - virtual QPixmap icon() const; virtual QWidget* configurationWidget(); virtual QWidget* aboutWidget(); @@ -98,9 +94,12 @@ public: virtual bool preventEnabling() const { return m_preventEnabling; } QString sendMessage( const QVariantMap& msg, QObject* receiver = 0, const QString& slot = QString() ); + void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater ); void unregisterUpdater( const QString& plid ); + bool deleteOnUnsync() const; + void setManualResolverPath( const QString& resolverPath ); public slots: @@ -134,21 +133,9 @@ private: void startPlaylistSync( SpotifyPlaylistInfo* playlist ); void stopPlaylistSync( SpotifyPlaylistInfo* playlist, bool forceDontDelete = false ); void fetchFullPlaylist( SpotifyPlaylistInfo* playlist ); + void setSyncForPlaylist( const QString& spotifyPlaylistId, bool sync ); - void stopPlaylistSubscribe( SpotifyPlaylistInfo* playlist ); - void startPlaylistSubscribe( SpotifyPlaylistInfo* playlist ); - - enum Actions{ - - None = 0x01, - Subscribe = 0x02, - Sync = 0x04, - UnSubscribe = 0x06, - UnSync = 0x08 - }; - - Actions m_action; void createActions(); void removeActions(); @@ -168,8 +155,6 @@ private: SmartPointerList< QAction > m_customActions; friend class ::SpotifyPlaylistUpdater; - - static SpotifyAccount* s_instance; }; } diff --git a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp index ec544b89b..64bdda98f 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.cpp @@ -74,7 +74,6 @@ SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const QStr , m_spotifyId( spotifyId ) , m_blockUpdatesForNextRevision( false ) , m_sync( false ) - , m_subscribe( false ) { init(); } @@ -195,14 +194,13 @@ SpotifyPlaylistUpdater::type() const QPixmap SpotifyPlaylistUpdater::typeIcon() const { - if ( !s_typePixmap ) { QPixmap pm( RESPATH "images/spotify-logo.png" ); s_typePixmap = new QPixmap( pm.scaled( 32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); } - if( !m_sync ) + if ( !m_sync ) return QPixmap(); return *s_typePixmap; @@ -222,17 +220,6 @@ SpotifyPlaylistUpdater::setSync( bool sync ) emit changed(); } -void -SpotifyPlaylistUpdater::setSubscribe( bool sub ) -{ - if ( m_subscribe == sub ) - return; - - m_subscribe = sub; - - saveToSettings(); - emit changed(); -} bool SpotifyPlaylistUpdater::sync() const @@ -240,14 +227,6 @@ SpotifyPlaylistUpdater::sync() const return m_sync; } -bool -SpotifyPlaylistUpdater::canSubscribe() -{ - - qDebug() << " canSubscribe " << m_spotify.data()->credentials().value( "username" ).toString() << m_spotifyId; - return !m_spotifyId.contains( m_spotify.data()->credentials().value( "username" ).toString() ); - -} void SpotifyPlaylistUpdater::spotifyTracksAdded( const QVariantList& tracks, const QString& startPosId, const QString& newRev, const QString& oldRev ) diff --git a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h index cabfb68b5..896e507d3 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h +++ b/src/libtomahawk/accounts/spotify/SpotifyPlaylistUpdater.h @@ -53,9 +53,6 @@ public: bool sync() const; void setSync( bool sync ); - bool canSubscribe(); - void setSubscribe( bool sub ); - bool subscribed() { return m_subscribe; } QString spotifyId() const { return m_spotifyId; } @@ -102,8 +99,6 @@ private: bool m_blockUpdatesForNextRevision; bool m_sync; - bool m_subscribe; - bool m_canSubscribe; QQueue<_detail::Closure*> m_queuedOps; #ifndef ENABLE_HEADLESS diff --git a/src/libtomahawk/utils/SpotifyParser.cpp b/src/libtomahawk/utils/SpotifyParser.cpp index 0e968b190..b03276412 100644 --- a/src/libtomahawk/utils/SpotifyParser.cpp +++ b/src/libtomahawk/utils/SpotifyParser.cpp @@ -116,7 +116,6 @@ SpotifyParser::lookupSpotifyBrowse( const QString& linkRaw ) type = DropJob::Track; QUrl url; - m_browseId = browseUri; if( type != DropJob::Artist ) url = QUrl( QString( SPOTIFY_PLAYLIST_API_URL "/browse/%1" ).arg( browseUri ) ); @@ -303,8 +302,6 @@ SpotifyParser::checkBrowseFinished() if( m_createNewPlaylist && !m_tracks.isEmpty() ) { - - m_playlist = Playlist::create( SourceList::instance()->getLocal(), uuid(), m_title, @@ -312,18 +309,6 @@ SpotifyParser::checkBrowseFinished() m_creator, false, m_tracks ); - - if( Tomahawk::Accounts::SpotifyAccount::instance() != 0 ) - { - - qDebug() << "FOUND SPOTIFY ACCOUNT!!" << Tomahawk::Accounts::SpotifyAccount::instance()->credentials().value("username") << Tomahawk::Accounts::SpotifyAccount::instance()->isAuthenticated(); - SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount::instance(), m_browseId, m_browseId, m_playlist ); - updater->setSync( true ); - updater->setSubscribe( false ); - Tomahawk::Accounts::SpotifyAccount::instance()->registerUpdaterForPlaylist( m_browseId, updater); - - } - connect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistCreated() ) ); return; } diff --git a/src/libtomahawk/utils/SpotifyParser.h b/src/libtomahawk/utils/SpotifyParser.h index 0cc5ea23e..7f5c65b61 100644 --- a/src/libtomahawk/utils/SpotifyParser.h +++ b/src/libtomahawk/utils/SpotifyParser.h @@ -28,8 +28,6 @@ #include #include #include -#include "accounts/spotify/SpotifyAccount.h" -#include "accounts/spotify/SpotifyPlaylistUpdater.h" #define SPOTIFY_PLAYLIST_API_URL "http://spotikea.tomahawk-player.org" @@ -86,7 +84,7 @@ private: QString m_title, m_info, m_creator; Tomahawk::playlist_ptr m_playlist; DropJobNotifier* m_browseJob; - QString m_browseId; + static QPixmap* s_pixmap; }; From 274d85216b8b9e4e787c7779059e0bb076e2d3c7 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Tue, 12 Jun 2012 22:16:54 +0000 Subject: [PATCH 392/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_bg.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_ca.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_de.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_en.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_es.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_fr.ts | 43 +++++++++++++++++++++++------------------- lang/tomahawk_ja.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_pl.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_pt_BR.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_ru.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_sv.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_tr.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_zh_CN.ts | 39 +++++++++++++++++++++----------------- lang/tomahawk_zh_TW.ts | 39 +++++++++++++++++++++----------------- 15 files changed, 344 insertions(+), 269 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 72fa376ff..2fb8e60b3 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -224,57 +224,57 @@ connect and stream from you? التالي - + Artist فنان - + Album البوم - + Owner المالك - + social اجتماعي - + love أحب - + Time الوقت - + Time Left الوقت المتبقي - + Shuffle خلط - + Repeat إعادة - + Low منخفض - + High مرتفع @@ -1088,17 +1088,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - الإستماع إلى "%1" ل%2 ومحبتها! %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - إنني أستمع إلى "%1" من قبل %2 على "%3" وقد أحببتها! %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left تبقى %1 حروف @@ -2626,7 +2631,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 إنني أستمع إلى "%1" من قبل %2 وقد أحببتها! %3 diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 8160aded9..85cac05c1 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -223,57 +223,57 @@ connect and stream from you? Следваща - + Artist Артист - + Album Албум - + Owner Притежател - + social социален - + love Харесай - + Time Продължителност - + Time Left Оставащо време - + Shuffle Разбъркано - + Repeat Повтори - + Low 0 - + High 100% @@ -1088,17 +1088,22 @@ Tomahaw създаде доклад относно това и изпращай Етикет - - Listening to "%1" by %2 and loving it! %3 - ♥ "%1" от %2 %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - #fb ♥ "%1" от %2 от "%3" %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left Остават още %1 символа @@ -2633,7 +2638,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 #fb ♥ "%1" от %2 %3 diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 5378b9648..a745a9ac0 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -223,57 +223,57 @@ connect and stream from you? Següent - + Artist Artista - + Album Àlbum - + Owner Propietari - + social social - + love M'encanta - + Time Temps - + Time Left Temps Restant - + Shuffle Mescla - + Repeat Repeteix - + Low Baix - + High Alt @@ -1086,17 +1086,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Estic escoltant "%1" de "%2" i m'encanta!%3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - Estic escoltant "%1" de "%2" a "%3" i m'encanta!%4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 caràcters restants @@ -2625,7 +2630,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Estic escoltant "%1" de "%2" i m'encanta! %3 diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index d3158a31b..29f878a63 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -223,57 +223,57 @@ connect and stream from you? Weiter - + Artist Künstler - + Album Album - + Owner Eigentümer - + social Sozial - + love Lieben - + Time Zeit - + Time Left Zeit verbleibend - + Shuffle Zufall - + Repeat Wiederholen - + Low Niedrig - + High Hoch @@ -1086,17 +1086,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Höre "%1" von %2 und liebe es! %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - Höre "%1" von %2 auf "%3" und liebe es! %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 Zeichen übrig @@ -2620,7 +2625,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Höre "%1" von %2 und liebe es! %3 diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index fd34c8768..fe3dc8b76 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -224,57 +224,57 @@ connect and stream from you? Next - + Artist Artist - + Album Album - + Owner Owner - + social social - + love love - + Time Time - + Time Left Time Left - + Shuffle Shuffle - + Repeat Repeat - + Low Low - + High High @@ -1087,17 +1087,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Listening to "%1" by %2 and loving it! %3 + + Tweet + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + Listening to "%1" by %2 on "%3". %4 + + + %1 characters left %1 characters left @@ -2626,7 +2631,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 6dc67a608..ba8303d9f 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -223,57 +223,57 @@ connect and stream from you? Siguiente - + Artist Artista - + Album Álbum - + Owner Propietario - + social social - + love favorita - + Time Duración - + Time Left Tiempo restante - + Shuffle Aleatorio - + Repeat Repetir - + Low Bajar volumen - + High Subir volumen @@ -1085,17 +1085,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 - Escuchando "%1" de %2 y me encanta! %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - Escuchando "%1" de %2 en "%3" y me encanta! %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 caracteres restantes @@ -2624,7 +2629,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 Escuchando "%1" de %2 y me encanta! %3 diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 66baafa21..35160f18f 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -224,57 +224,57 @@ se connecter et streamer depuis chez vous ? Suivant - + Artist Artiste - + Album Album - + Owner Propriétaire - + social social - + love love - + Time Durée - + Time Left Durée restante - + Shuffle Lecture Aléatoire - + Repeat Répéter - + Low Bas - + High Haut @@ -1087,17 +1087,22 @@ se connecter et streamer depuis chez vous ? TextLabel - - Listening to "%1" by %2 and loving it! %3 - J'écoute "%1" par %2 et j'adore ! %3 + + Tweet + - - Listening to "%1" by %2 on "%3" and loving it! %4 - J'écoute "%1" par %2 sur "%3" et j'adore ! %4 + + Listening to "%1" by %2. %3 + - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 caractères restants @@ -2626,7 +2631,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 J'écoute "%1" par %2 et j'adore ! %3 diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index cf7d4f67d..a07497888 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -223,57 +223,57 @@ connect and stream from you? 次へ - + Artist アーティスト - + Album アルバム - + Owner - + social ソーシャル - + love Love - + Time 時間 - + Time Left 残り時間 - + Shuffle シャッフル - + Repeat リピート - + Low - + High @@ -1087,17 +1087,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -2616,7 +2621,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index d1e41f35b..d186416b5 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -223,57 +223,57 @@ connect and stream from you? Następny - + Artist Artysta - + Album Album - + Owner Właściciel - + social - + love ulubione - + Time Czas - + Time Left Pozostały czas - + Shuffle Losowo - + Repeat Powtarzaj - + Low Nisko - + High Wysoko @@ -1085,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left pozostało znaków: %1 @@ -2620,7 +2625,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 3838d9104..fb9c3beb1 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -223,57 +223,57 @@ connect and stream from you? Próxima - + Artist Artista - + Album Álbum - + Owner Proprietário - + social - + love Favorita - + Time Tempo - + Time Left Tempo restante - + Shuffle Embaralhar - + Repeat Repetir - + Low Diminuir - + High Aumentar @@ -1085,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -2619,7 +2624,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 0d441c384..595661493 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -224,57 +224,57 @@ connect and stream from you? Следующая - + Artist Исполнитель - + Album Альбом - + Owner Владелец - + social социальный - + love Любимая - + Time Прошло - + Time Left Осталось - + Shuffle Случаная - + Repeat Повторять - + Low Тише - + High Громче @@ -1087,17 +1087,22 @@ connect and stream from you? TextLabel - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left %1 символов осталось @@ -2621,7 +2626,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 88f4ccce8..11ce88dff 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -223,57 +223,57 @@ connect and stream from you? Nästa - + Artist Artist - + Album Album - + Owner Ägare - + social - + love älska - + Time Tid - + Time Left Tid kvar - + Shuffle Blanda - + Repeat Upprepa - + Low Låg - + High Hög @@ -1086,17 +1086,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -2615,7 +2620,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index da813a754..a01a24047 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -223,57 +223,57 @@ connect and stream from you? Sonraki - + Artist Sanatçı - + Album Albüm - + Owner Sahibi - + social - + love beğen - + Time Süre - + Time Left Kalan Süre - + Shuffle Karışık - + Repeat Yenile - + Low Düşük - + High Yüksek @@ -1085,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -2614,7 +2619,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 25858013b..50626f41a 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -223,57 +223,57 @@ connect and stream from you? 下一首 - + Artist 艺人 - + Album 专辑 - + Owner - + social - + love - + Time - + Time Left - + Shuffle 无序播放 - + Repeat 重复播放 - + Low - + High @@ -1085,17 +1085,22 @@ connect and stream from you? - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -2614,7 +2619,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 0ba0ae65d..347560dac 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -223,57 +223,57 @@ connect and stream from you? 下一首 - + Artist 演出者 - + Album 專輯 - + Owner 擁有人 - + social - + love 喜愛 - + Time 時間 - + Time Left 剩餘時間 - + Shuffle 隨機 - + Repeat 重複 - + Low - + High @@ -1085,17 +1085,22 @@ connect and stream from you? 文字標籤 - - Listening to "%1" by %2 and loving it! %3 + + Tweet - - Listening to "%1" by %2 on "%3" and loving it! %4 + + Listening to "%1" by %2. %3 - + + Listening to "%1" by %2 on "%3". %4 + + + + %1 characters left @@ -2614,7 +2619,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::TwitterInfoPlugin - + Listening to "%1" by %2 and loving it! %3 From 0bb74d949f234c738fd28cb247b95fc6f20b6672 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 01:24:12 +0200 Subject: [PATCH 393/433] * Fixed NSIS template. --- CMakeModules/NSIS.template.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeModules/NSIS.template.in b/CMakeModules/NSIS.template.in index 2e1aa7c93..f3db07863 100644 --- a/CMakeModules/NSIS.template.in +++ b/CMakeModules/NSIS.template.in @@ -278,7 +278,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER File "${INSTALL_PATH}\bin\libqxtweb-standalone.dll" File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll" - File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll" File "${INSTALL_PATH}\bin\libtomahawklib.dll" ; plugins File "${INSTALL_PATH}\lib\libtomahawk_*_*.dll" @@ -293,7 +292,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER File "${BUILD_PATH}\libtomahawklib.dll" File "${BUILD_PATH}\libqxtweb-standalone.dll" File "${BUILD_PATH}\libtomahawk_portfwd.dll" - File "${BUILD_PATH}\libtomahawk_lastfm2.dll" ; plugins File "${BUILD_PATH}\libtomahawk_*_*.dll" !endif @@ -351,6 +349,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER File "${MING_BIN}\zlib1.dll" File "${MING_BIN}\libechonest.dll" + File "${MING_BIN}\liblastfm.dll" File "${MING_BIN}\libQTweetLib.dll" File "${MING_BIN}\libquazip.dll" From 9935aca12734997b072f0a774fadd060e316b903 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 08:48:38 +0200 Subject: [PATCH 394/433] * New artist page. Tweaks, shadows etc. coming. --- .../widgets/infowidgets/ArtistInfoWidget.cpp | 62 ++++- .../widgets/infowidgets/ArtistInfoWidget.h | 1 + .../widgets/infowidgets/ArtistInfoWidget.ui | 239 ++++++++++++------ 3 files changed, 217 insertions(+), 85 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 8bbcda7bb..72519dd2b 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -21,6 +21,8 @@ #include "ArtistInfoWidget_p.h" #include "ui_ArtistInfoWidget.h" +#include + #include "audio/AudioEngine.h" #include "playlist/PlayableModel.h" #include "playlist/TreeModel.h" @@ -31,12 +33,11 @@ #include "database/DatabaseCommand_AllTracks.h" #include "database/DatabaseCommand_AllAlbums.h" +#include "Pipeline.h" #include "utils/StyleHelper.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" -#include "Pipeline.h" - using namespace Tomahawk; @@ -45,15 +46,15 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* , ui( new Ui::ArtistInfoWidget ) , m_artist( artist ) { - ui->setupUi( this ); + QWidget* widget = new QWidget; + ui->setupUi( widget ); m_plInterface = Tomahawk::playlistinterface_ptr( new MetaPlaylistInterface( this ) ); - TomahawkUtils::unmarginLayout( layout() ); - TomahawkUtils::unmarginLayout( ui->layoutWidget->layout() ); +/* TomahawkUtils::unmarginLayout( ui->layoutWidget->layout() ); TomahawkUtils::unmarginLayout( ui->layoutWidget1->layout() ); TomahawkUtils::unmarginLayout( ui->layoutWidget2->layout() ); - TomahawkUtils::unmarginLayout( ui->albumHeader->layout() ); + TomahawkUtils::unmarginLayout( ui->albumHeader->layout() );*/ m_albumsModel = new PlayableModel( ui->albums ); ui->albums->setPlayableModel( m_albumsModel ); @@ -70,11 +71,56 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* ui->topHits->setSortingEnabled( false ); ui->topHits->setEmptyTip( tr( "Sorry, we could not find any top hits for this artist!" ) ); + ui->relatedArtists->setAutoFitItems( false ); + ui->relatedArtists->setWrapping( false ); + ui->relatedArtists->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + ui->relatedArtists->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + m_relatedModel->setItemSize( QSize( 170, 170 ) ); + ui->albums->setAutoFitItems( false ); + ui->albums->setWrapping( false ); + ui->albums->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + ui->albums->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + m_albumsModel->setItemSize( QSize( 170, 170 ) ); + + ui->topHits->setFrameShape( QFrame::StyledPanel ); + ui->topHits->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); + ui->cover->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, QSize( ui->cover->sizeHint() ) ) ); connect( m_albumsModel, SIGNAL( loadingStarted() ), SLOT( onLoadingStarted() ) ); connect( m_albumsModel, SIGNAL( loadingFinished() ), SLOT( onLoadingFinished() ) ); + ui->biography->setStyleSheet( "QTextBrowser#biography { background-color: transparent; }" ); + ui->biography->setFrameShape( QFrame::NoFrame ); + ui->biography->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + QPalette p = ui->biography->palette(); + p.setColor( QPalette::Foreground, Qt::white ); + p.setColor( QPalette::Text, Qt::white ); + + ui->biography->setPalette( p ); + ui->label->setPalette( p ); + ui->label_2->setPalette( p ); + ui->label_3->setPalette( p ); + + ui->label->setContentsMargins( 0, 0, 0, 0 ); + ui->label_2->setContentsMargins( 0, 16, 0, 0 ); + ui->label_3->setContentsMargins( 0, 16, 0, 0 ); + + QScrollArea* area = new QScrollArea(); + area->setWidgetResizable( true ); + area->setWidget( widget ); + + area->setStyleSheet( "QScrollArea { background-color: #323435; }" ); + area->setFrameShape( QFrame::NoFrame ); + area->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->addWidget( area ); + setLayout( layout ); + TomahawkUtils::unmarginLayout( layout ); + load( artist ); } @@ -207,6 +253,8 @@ ArtistInfoWidget::onBiographyLoaded() { m_longDescription = m_artist->biography(); emit longDescriptionChanged( m_longDescription ); + + ui->biography->setHtml( m_artist->biography() ); } @@ -218,6 +266,8 @@ ArtistInfoWidget::onArtistImageUpdated() m_pixmap = m_artist->cover( QSize( 0, 0 ) ); emit pixmapChanged( m_pixmap ); + + ui->cover->setPixmap( m_artist->cover( ui->cover->sizeHint() ) ); } diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index 6c00ab0f2..9e1ac0279 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -76,6 +76,7 @@ public: virtual bool isTemporaryPage() const { return true; } virtual bool showStatsBar() const { return false; } + virtual bool showInfoBar() const { return false; } virtual bool jumpToCurrentTrack(); virtual bool isBeingPlayed() const; diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index 246a3e593..ee1003bb8 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -6,84 +6,180 @@ 0 0 - 902 - 696 + 965 + 812 Form - + - - - Qt::Vertical + + + 16 - - 1 + + 12 - - - Qt::Horizontal - - - 1 - - - - - - - Top Hits - - - - - - - true - - - - - - - - - - - Related Artists - - - - - - - - - - - - + + 16 + + + - - - - - - Albums - - - - + + + + 20 + 75 + true + + + + Top Hits + + + 0 + - + + + + 0 + 300 + + + + true + + + + + + + + Arial + 20 + 75 + true + + + + Related Artists + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 190 + + + + + + + + + Arial + 20 + 75 + true + true + + + + Albums + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 190 + + + - - + + + + + 16 + + + + + + 0 + 0 + + + + + 220 + 220 + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 240 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + + @@ -93,21 +189,6 @@ QTreeView

    playlist/PlaylistView.h
    - - HeaderLabel - QLabel -
    widgets/HeaderLabel.h
    -
    - - HeaderWidget - QWidget -
    widgets/HeaderWidget.h
    -
    - - ToggleButton - QPushButton -
    widgets/ToggleButton.h
    -
    GridView QListView From 339e9a3869ada7741d4e01815fc6905c1b7298f9 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 13 Jun 2012 09:15:55 +0200 Subject: [PATCH 395/433] TWK-579: Always set stretch factor to avoid super wide default widths --- src/TomahawkWindow.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp index 1a7734404..83db1ba4e 100644 --- a/src/TomahawkWindow.cpp +++ b/src/TomahawkWindow.cpp @@ -160,11 +160,12 @@ TomahawkWindow::loadSettings() restoreState( s->mainWindowState() ); if ( !s->mainWindowSplitterState().isEmpty() ) ui->splitter->restoreState( s->mainWindowSplitterState() ); - else - { - ui->splitter->setStretchFactor( 0, 0 ); - ui->splitter->setStretchFactor( 1, 1 ); - } + + // Always set stretch factor. If user hasn't manually set splitter sizes, + // this will ensure a sane default on all startups. If the user has, the manual + // size will override the default stretching + ui->splitter->setStretchFactor( 0, 0 ); + ui->splitter->setStretchFactor( 1, 1 ); #ifdef QT_MAC_USE_COCOA if ( workaround ) From 1a52b99d4f1fe4f95c5873e8497750786bcce8d9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 09:16:34 +0200 Subject: [PATCH 396/433] * Cleanup ui file. --- src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index ee1003bb8..d56a38610 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -7,7 +7,7 @@ 0 0 965 - 812 + 824 @@ -25,6 +25,9 @@ 16 + + 12 + @@ -148,7 +151,7 @@ - TextLabel + Cover Qt::AlignCenter From 52dcf924a40c26c38225a35a1da59be4a87530a4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 09:17:20 +0200 Subject: [PATCH 397/433] * New track page. Again, still a bit WIP. --- .../widgets/infowidgets/TrackInfoWidget.cpp | 29 +- .../widgets/infowidgets/TrackInfoWidget.ui | 389 ++++++++---------- 2 files changed, 200 insertions(+), 218 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 20837b978..74cdab9ad 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -21,6 +21,8 @@ #include "TrackInfoWidget.h" #include "ui_TrackInfoWidget.h" +#include + #include "ViewManager.h" #include "SourceList.h" #include "playlist/PlayableModel.h" @@ -36,7 +38,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par : QWidget( parent ) , ui( new Ui::TrackInfoWidget ) { - ui->setupUi( this ); + QWidget* widget = new QWidget; + ui->setupUi( widget ); QPalette pal = palette(); pal.setColor( QPalette::Window, QColor( "#323435" ) ); @@ -44,8 +47,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par setPalette( pal ); setAutoFillBackground( true ); - layout()->setSpacing( 0 ); - ui->tracksWidget->setStyleSheet( "QWidget#tracksWidget { background-color: #323435; }" ); +// layout()->setSpacing( 0 ); +// ui->tracksWidget->setStyleSheet( "QWidget#tracksWidget { background-color: #323435; }" ); // ui->headerWidget->setStyleSheet( "QWidget#headerWidget { background-image: url(" RESPATH "images/playlist-header-tiled.png); }" ); // ui->headerWidget->setStyleSheet( "background-color: #323435;" ); // ui->tracksWidget->setStyleSheet( "background-color: #323435;" ); @@ -64,8 +67,6 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par f.setPixelSize( 14 ); ui->artistLabel->setFont( f ); ui->albumLabel->setFont( f ); - ui->byLabel->setFont( f ); - ui->fromLabel->setFont( f ); f.setPixelSize( 12 ); ui->statsLabel->setFont( f ); @@ -79,9 +80,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->trackLabel->setPalette( p ); ui->artistLabel->setPalette( p ); ui->albumLabel->setPalette( p ); - ui->byLabel->setPalette( p ); - ui->fromLabel->setPalette( p ); ui->lyricsView->setPalette( p ); + ui->label->setPalette( p ); // ui->similarTracksLabel->setPalette( p ); ui->artistLabel->setType( QueryLabel::Artist ); @@ -93,6 +93,20 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->similarTracksView->setEmptyTip( tr( "Sorry, but we could not find similar tracks for this song!" ) ); m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); + ui->cover->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultTrackImage, TomahawkUtils::ScaledCover, QSize( ui->cover->sizeHint() ) ) ); + + QScrollArea* area = new QScrollArea(); + area->setWidgetResizable( true ); + area->setWidget( widget ); + + area->setStyleSheet( "QScrollArea { background-color: #323435; }" ); + area->setFrameShape( QFrame::NoFrame ); + area->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->addWidget( area ); + setLayout( layout ); + TomahawkUtils::unmarginLayout( layout ); load( query ); @@ -159,7 +173,6 @@ TrackInfoWidget::load( const query_ptr& query ) ui->trackLabel->setText( query->track() ); ui->artistLabel->setQuery( query ); ui->albumLabel->setQuery( query ); - ui->fromLabel->setVisible( !query->album().isEmpty() ); m_relatedTracksModel->clear(); diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui index 088f5b234..1004806b6 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.ui @@ -6,219 +6,193 @@ 0 0 - 852 - 571 + 951 + 771 Form - - - 0 - + - - - - 12 - - - - - - 0 - 0 - - - - - 128 - 128 - - - - Cover - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 16 - 20 - - - - - - - - - - Track - - - - - - - - - - 0 - 0 - - - - by - - - - - - - Artist - - - - - - - - - - - - 0 - 0 - - - - from - - - - - - - Album - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 16 - 20 - - - - - - - - Statistics - - - Qt::AlignCenter - - - - - - - - - - Lyrics + + + 16 - - 8 + + 12 - - - - - - false + + 16 - - - - - - - 0 - - - 0 - - - 4 - - - 0 - - - 0 - - - - - Similar Tracks - - - 8 - - - - - - - - 0 - 0 - - - - - - + + 12 + + + + + + + + Arial + 20 + 75 + true + + + + Similar Tracks + + + 0 + + + + + + + + 0 + 0 + + + + + + + + + + 16 + + + + + + 0 + 0 + + + + + 220 + 220 + + + + Cover + + + Qt::AlignCenter + + + + + + + + + Track + + + Qt::AlignCenter + + + + + + + + + Artist + + + Qt::AlignCenter + + + + + + + + + + + Album + + + Qt::AlignCenter + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 12 + + + + + + + + Statistics + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 12 + + + + + + + + + 0 + 0 + + + + + 300 + 0 + + + + false + + + + + + @@ -226,12 +200,7 @@ GridView QListView -
    playlist/GridView.h
    -
    - - HeaderLabel - QLabel -
    widgets/HeaderLabel.h
    +
    GridView.h
    QueryLabel From 236fe9164661fa3c68fc946135aaa8cd97672a73 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 09:39:03 +0200 Subject: [PATCH 398/433] * Try fixing solid bg color on OSX. --- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 74cdab9ad..3364575b4 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -44,8 +44,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par QPalette pal = palette(); pal.setColor( QPalette::Window, QColor( "#323435" ) ); - setPalette( pal ); - setAutoFillBackground( true ); + widget->setPalette( pal ); + widget->setAutoFillBackground( true ); // layout()->setSpacing( 0 ); // ui->tracksWidget->setStyleSheet( "QWidget#tracksWidget { background-color: #323435; }" ); From e3aefb78f7bf22c5ffa00bc9f76d9593bf246fc3 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 09:56:38 +0200 Subject: [PATCH 399/433] * Fixed artist page's bg color on OSX. --- src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 72519dd2b..8732596c0 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -49,6 +49,12 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* QWidget* widget = new QWidget; ui->setupUi( widget ); + QPalette pal = palette(); + pal.setColor( QPalette::Window, QColor( "#323435" ) ); + + widget->setPalette( pal ); + widget->setAutoFillBackground( true ); + m_plInterface = Tomahawk::playlistinterface_ptr( new MetaPlaylistInterface( this ) ); /* TomahawkUtils::unmarginLayout( ui->layoutWidget->layout() ); From 2656c4f3f3fd0943c5b95cb7d00cc1306fa6bba5 Mon Sep 17 00:00:00 2001 From: Jason Herskowitz Date: Wed, 13 Jun 2012 10:22:06 -0400 Subject: [PATCH 400/433] Swap placement of Albums and Related Artists on new album page and shrink label size a few points --- .../widgets/infowidgets/ArtistInfoWidget.ui | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index d56a38610..9254495a6 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -7,7 +7,7 @@ 0 0 965 - 824 + 844 @@ -34,7 +34,7 @@ - 20 + 16 75 true @@ -65,13 +65,13 @@ Arial - 20 + 16 75 true - Related Artists + Albums 0 @@ -79,7 +79,7 @@ - + 0 @@ -99,14 +99,14 @@ Arial - 20 + 16 75 true true - Albums + Related Artists 0 @@ -114,7 +114,7 @@ - + 0 @@ -150,6 +150,11 @@ 220 + + + 12 + + Cover @@ -172,6 +177,11 @@ 240 + + + 13 + + Qt::ScrollBarAlwaysOff From 9c9dbb33c43d973202e4c31f7188df115ee9dc09 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 13 Jun 2012 20:45:17 +0200 Subject: [PATCH 401/433] Revert "Swap placement of Albums and Related Artists on new album page and shrink label size a few points" This reverts commit 2656c4f3f3fd0943c5b95cb7d00cc1306fa6bba5. --- .../widgets/infowidgets/ArtistInfoWidget.ui | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index 9254495a6..d56a38610 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -7,7 +7,7 @@ 0 0 965 - 844 + 824 @@ -34,7 +34,7 @@ - 16 + 20 75 true @@ -65,13 +65,13 @@ Arial - 16 + 20 75 true - Albums + Related Artists 0 @@ -79,7 +79,7 @@ - + 0 @@ -99,14 +99,14 @@ Arial - 16 + 20 75 true true - Related Artists + Albums 0 @@ -114,7 +114,7 @@ - + 0 @@ -150,11 +150,6 @@ 220 - - - 12 - - Cover @@ -177,11 +172,6 @@ 240 - - - 13 - - Qt::ScrollBarAlwaysOff From 7b1a586a8bed0d55a9397230704fc36cdadeb2eb Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Wed, 13 Jun 2012 22:16:55 +0000 Subject: [PATCH 402/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 134 +++++++++++++++++++---------------------- lang/tomahawk_bg.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_ca.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_de.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_en.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_es.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_fr.ts | 134 +++++++++++++++++++---------------------- lang/tomahawk_ja.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_pl.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_pt_BR.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_ru.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_sv.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_tr.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_zh_CN.ts | 128 ++++++++++++++++++--------------------- lang/tomahawk_zh_TW.ts | 128 ++++++++++++++++++--------------------- 15 files changed, 891 insertions(+), 1041 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 2fb8e60b3..4555445c1 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -171,32 +171,37 @@ connect and stream from you? استمارة - + Top Hits الأكثر شهرة - + Related Artists الفنانين ذات الذوق القريب - + Albums ألبومات - + + Cover + + + + Sorry, we could not find any albums for this artist! نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! - + Sorry, we could not find any related artists! نعتذر، لم نستطيع إيجاد فنانين! - + Sorry, we could not find any top hits for this artist! نعتذر، لم نستطيع إيجاد أغاني مشهورة جدا لهذا الفنان! @@ -1090,17 +1095,17 @@ connect and stream from you? Tweet - + تويت (Tweet) Listening to "%1" by %2. %3 - + إنني أستمع إلى "%1" من قبل %2. %3 Listening to "%1" by %2 on "%3". %4 - + إنني أستمع إلى "%1" من قبل %2 على "%3". %4 @@ -3011,7 +3016,7 @@ enter the displayed PIN number here: - + Play إستمع @@ -3031,172 +3036,172 @@ enter the displayed PIN number here: التالي - + Back إلى الوراء - + Go back one page العودة صفحة واحدة إلى الوراء - + Forward تقدم - + Go forward one page تقدم صفحة واحدة - + Global Search... بحث شامل... - - + + Check For Updates... التحقق من التحديثات... - - - + + + Connect To Peer ربط بالند - + Enter peer address: أدخل عنوان الند: - + Enter peer port: أدخل بوابة الند: - + Enter peer key: أدخل مفتاح الند: - + XSPF Error خطأ XSPF - + This is not a valid XSPF playlist. قائمة الأغاني XSPF هذه ليست صالحة. - + Failed to save tracks فشل في حفظ الأغاني - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. بعض الأغاني في قائمة الأغاني لا تحتوي على إسم الفنان أو إسم الأغنية. هذه الأغاني سوف تتجاهل. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. تأكد أن لديك خلفية فونون المناسبة والإضافات المطلوبة مثبتة. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. عذرا، هناك مشكلة في الوصول إلى جهاز الصوت أو الأغنية المطلوب، سوف يتم تخطي الأغنية الحالية. - + Station إذاعة - + Create New Station إنشاء قائمة أغاني جديدة - + Name: الاسم: - + Playlist قائمة الأغاني - + Automatic Playlist قائمة أغاني أوتوماتيكية - + Pause تعليق - + Go &offline أصبح &غير متصل - + Go &online اصبح &متصل - + Authentication Error خطأ في المصادقة - + Error connecting to SIP: Authentication failed! خطأ في الاتصال بسيب (SIP): فشلت المصادقة! - + %1 by %2 track, artist name %1 من قبل %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 حقوق الطبع والنشر ٢٠١٠ - ٢٠١٢ - + Thanks to: شكر لكل من: - + About Tomahawk عن توماهوك @@ -3280,47 +3285,32 @@ enter the displayed PIN number here: استمارة - + Cover غلاف - + Track اغنية - - by - من قبل - - - + Artist فنان - - from - من - - - + Album البوم - + Statistics إحصائيات - - Lyrics - كلمات - - - + Similar Tracks أغاني قريبة @@ -3330,27 +3320,27 @@ enter the displayed PIN number here: نعتذر، لم نستطيع إيجاد أغاني قريبة من هذه الأغنية! - + You've listened to this track %n time(s). لقد استمعت إلى هذه الأغنية %n مرة.لقد استمعت إلى هذه الأغنية مرة %n.لقد استمعت إلى هذه الأغنية مرتين %n.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات. - + You've never listened to this track before. لم تستمع لهذه الأغنية من قبل. - + You first listened to it on %1. استمعت إليها أولاً في %1. - + You've listened to %1 %n time(s). لقد استمعت إلى %1 %n مرة.لقد استمعت إلى %1 مرة %n.لقد استمعت إلى %1 مرتين %n.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات. - + You've never listened to %1 before. لم تستمع إلى %1 من قبل. diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 85cac05c1..ba813278f 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -170,32 +170,37 @@ connect and stream from you? - + Top Hits Най-големи хитове - + Related Artists Свързани артисти - + Albums Албуми - + + Cover + + + + Sorry, we could not find any albums for this artist! Съжалявам, но не откривам нито един албум за този артист! - + Sorry, we could not find any related artists! Съжалявам, но не откривам нито един подобен на този артист! - + Sorry, we could not find any top hits for this artist! Съжалявам, но не откривам нито една хитова песен на този артист! @@ -3018,7 +3023,7 @@ enter the displayed PIN number here: - + Play Изпълни @@ -3038,175 +3043,175 @@ enter the displayed PIN number here: Следваща - + Back - + Go back one page Една страница назад - + Forward Напред - + Go forward one page Една страница напред - + Global Search... Глобално търсене... - - + + Check For Updates... Провери за обновления... - - - + + + Connect To Peer Свържи се с друг потребител - + Enter peer address: Въведи адресът на отдалеченият потребител: - + Enter peer port: Въведи порт: - + Enter peer key: Въведи ключът за удостоверяване: - + XSPF Error XSPF Грешка - + This is not a valid XSPF playlist. Това не е валиден XSPF списък - + Failed to save tracks Не мога да запазя списъкът с песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Някои от песните в този списък нямат артист и заглавие. Те ще бъдат игнорирани. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраната песен - тя ще бъде прескочена. Моля, увери се, че са инсталирани подходящ Phonon и приставки. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Съжалявам. Има проблем с достъпа до твоето аудио устройство или избраната песен. Тя ще бъде пропусната. - + Station Станция - + Create New Station Създай нова станция - + Name: Име: - + Playlist Списък - + Automatic Playlist Автоматично-генериран списък - + Pause Пауза - + Go &offline Излез &извън линия - + Go &online Свържи &се - + Authentication Error Грешка при удостоверяване - + Error connecting to SIP: Authentication failed! Грешка при свързване: Неуспешно удостоверяване! - + %1 by %2 track, artist name %1 от %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Всички права - запазени. 2010 - 2012 - + Thanks to: Благодарности на: - + About Tomahawk Относно Tomahawk @@ -3290,47 +3295,32 @@ enter the displayed PIN number here: - + Cover Обложка - + Track Песен - - by - от - - - + Artist Изпълнител - - from - от - - - + Album Албум - + Statistics Статистика - - Lyrics - Текст - - - + Similar Tracks Подобни песни @@ -3340,27 +3330,27 @@ enter the displayed PIN number here: Съжалявам, но не откривам нито една подобна на тази песен! - + You've listened to this track %n time(s). Ти си слушал тази песен %n път(и)Ти си слушал тази песен %n път(и) - + You've never listened to this track before. Никога не си слушал тази песен преди - + You first listened to it on %1. Първоначално си я слушал на %1 - + You've listened to %1 %n time(s). Слушал си %1 път(и)Слушал си %1 %n път(и) - + You've never listened to %1 before. Никога не си слушал %1 преди diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index a745a9ac0..418a138ff 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -170,32 +170,37 @@ connect and stream from you? Formulari - + Top Hits Grans Èxits - + Related Artists Artistes Relacionats - + Albums Àlbums - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3010,7 +3015,7 @@ introduïu el PIN aquí: - + Play Reprodueix @@ -3030,172 +3035,172 @@ introduïu el PIN aquí: Següent - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Cerca Global... - - + + Check For Updates... Comprova les actualitzacions... - - - + + + Connect To Peer Connexió Remota - + Enter peer address: Introduïu l'adreça remota: - + Enter peer port: Introduïu el port remot: - + Enter peer key: Introduïu la clau remota: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. No és una llista XSPF vàlida. - + Failed to save tracks Error en desar les cançons - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunes cançons de la llista no contenen ni artista ni titol i s'han ignorat. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Hi ha un problema per accedir al dispositiu de so o a la cançó. La cançó actual s'ha saltat. Assegureu-vos que teniu un back.end de Phonon adequant i els plugins necessaris instal·lats. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Hi ha un problema per accedir al dispositiu de so o a la cançó, la cançó actual s'ha saltat. - + Station - + Create New Station Crea una Nova Emissora - + Name: Nom: - + Playlist - + Automatic Playlist - + Pause Pausa - + Go &offline &Desconnecta't - + Go &online &Connecta't - + Authentication Error Error d'autentificació - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Quant a Tomahawk @@ -3279,47 +3284,32 @@ introduïu el PIN aquí:
    Formulari - + Cover Cover - + Track Cançó - - by - de - - - + Artist Artista - - from - de - - - + Album Àlbum - + Statistics Estadístiques - - Lyrics - - - - + Similar Tracks Cançons Semblants @@ -3329,27 +3319,27 @@ introduïu el PIN aquí:
    - + You've listened to this track %n time(s). Heu escoltat aquesta cançó %n cop.Heu escoltat aquesta cançó %n cops. - + You've never listened to this track before. No heu escoltat mai aquesta cançó abans. - + You first listened to it on %1. Vau escoltar aquesta cançó per primer cop el %1. - + You've listened to %1 %n time(s). Heu escoltat %1 %n cop.Heu escoltat %1 %n cops. - + You've never listened to %1 before. No heu escoltat mai %1 abans. diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 29f878a63..47d331b6d 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -170,32 +170,37 @@ connect and stream from you? Form - + Top Hits Top Hits - + Related Artists Ähnliche Künstler - + Albums Alben - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3005,7 +3010,7 @@ Tomahawk auf Twitter's Website authentifiziert hast: - + Play Abspielen @@ -3025,172 +3030,172 @@ Tomahawk auf Twitter's Website authentifiziert hast:
    Weiter - + Back Zurück - + Go back one page Gehe eine Seite zurück - + Forward Vorwärts - + Go forward one page Gehe eine Seite vorwärts - + Global Search... Globale Suche... - - + + Check For Updates... Nach Updates suchen... - - - + + + Connect To Peer Mit anderem Tomahawk verbinden - + Enter peer address: Gib die Adresse der Gegenstelle ein: - + Enter peer port: Gib den Port der Gegenstelle ein: - + Enter peer key: Gib den Schlüssel der Gegenstelle ein: - + XSPF Error XSPF-Fehler - + This is not a valid XSPF playlist. Dies ist keine gültige XSPF-Playliste. - + Failed to save tracks Konnte Stücke nicht abspeichern - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Einige Stücke in der Playliste enthalten weder Künstler noch Titel. Diese werden ignoriert. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. Vergewisser dich, dass ein geignetes Phonon-Backend mitsamt benötigten Plugins installiert ist. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Es tut uns leid, Tomahawk kann auf dein Audio-Gerät oder das gewünschte Stück nicht zugreifen und überspringt es deshalb. - + Station - + Create New Station Neue Station erstellen - + Name: Name: - + Playlist - + Automatic Playlist - + Pause Pause - + Go &offline Verbindung &trennen - + Go &online &Verbindung herstellen - + Authentication Error Authentifizierungsfehler - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 von %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Über Tomahawk @@ -3274,47 +3279,32 @@ Tomahawk auf Twitter's Website authentifiziert hast:
    Formular - + Cover Cover - + Track Lied - - by - von - - - + Artist Künstler - - from - auf - - - + Album Album - + Statistics Statistiken - - Lyrics - Liedtext - - - + Similar Tracks Ähnliche Lieder @@ -3324,27 +3314,27 @@ Tomahawk auf Twitter's Website authentifiziert hast:
    - + You've listened to this track %n time(s). Du hast dieses Lied einmal gehört.Du hast dieses Lied %n mal gehört. - + You've never listened to this track before. Du hast dieses Lied noch nie angehört. - + You first listened to it on %1. Du hast dieses Lied zum ersten mal am %1 gehört. - + You've listened to %1 %n time(s). Du hast %1 einmal angehört.Du hast %1 %n mal angehört. - + You've never listened to %1 before. Du hast %1 vorher noch nie gehört. diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index fe3dc8b76..3a8bd9116 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -171,32 +171,37 @@ connect and stream from you? Form - + Top Hits Top Hits - + Related Artists Related Artists - + Albums Albums - + + Cover + Cover + + + Sorry, we could not find any albums for this artist! Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! Sorry, we could not find any top hits for this artist! @@ -3011,7 +3016,7 @@ enter the displayed PIN number here:
    - + Play Play @@ -3031,172 +3036,172 @@ enter the displayed PIN number here:
    Next - + Back Back - + Go back one page Go back one page - + Forward Forward - + Go forward one page Go forward one page - + Global Search... Global Search... - - + + Check For Updates... Check For Updates... - - - + + + Connect To Peer Connect To Peer - + Enter peer address: Enter peer address: - + Enter peer port: Enter peer port: - + Enter peer key: Enter peer key: - + XSPF Error XSPF Error - + This is not a valid XSPF playlist. This is not a valid XSPF playlist. - + Failed to save tracks Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station Station - + Create New Station Create New Station - + Name: Name: - + Playlist Playlist - + Automatic Playlist Automatic Playlist - + Pause Pause - + Go &offline Go &offline - + Go &online Go &online - + Authentication Error Authentication Error - + Error connecting to SIP: Authentication failed! Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Copyright 2010 - 2012 - + Thanks to: Thanks to: - + About Tomahawk About Tomahawk @@ -3280,47 +3285,32 @@ enter the displayed PIN number here:
    Form - + Cover Cover - + Track Track - - by - by - - - + Artist Artist - - from - from - - - + Album Album - + Statistics Statistics - - Lyrics - Lyrics - - - + Similar Tracks Similar Tracks @@ -3330,27 +3320,27 @@ enter the displayed PIN number here:
    Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). You've listened to this track %n time(s).You've listened to this track %n time(s). - + You've never listened to this track before. You've never listened to this track before. - + You first listened to it on %1. You first listened to it on %1. - + You've listened to %1 %n time(s). You've listened to %1 %n time(s).You've listened to %1 %n time(s). - + You've never listened to %1 before. You've never listened to %1 before. diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index ba8303d9f..61fe02437 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -170,32 +170,37 @@ connect and stream from you? Formulario - + Top Hits Grandes éxitos - + Related Artists Artistas relacionados - + Albums Álbumes - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3009,7 +3014,7 @@ introduzca su número PIN aquí:
    - + Play Reproducir @@ -3029,172 +3034,172 @@ introduzca su número PIN aquí:
    Siguiente - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Búsqueda global... - - + + Check For Updates... Buscar actualizaciones... - - - + + + Connect To Peer Conectar a un par - + Enter peer address: Introducir dirección del par: - + Enter peer port: Introducir puerto del par: - + Enter peer key: Introducir contraseña del par: - + XSPF Error Error XSPF - + This is not a valid XSPF playlist. Esta no es una lista de reproducción XSPF válida. - + Failed to save tracks Fallo al guardar pistas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algunas pistas en la lista de reproducción no contienen artista ni título. Serán ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. Asegúrese de que ha instalado un backend de Phonon adecuado y los plugins necesarios. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Se ha producido un error al acceder al dispostivo de audio o al tema deseado y se va saltar. - + Station - + Create New Station Crear nueva estación - + Name: Nombre: - + Playlist - + Automatic Playlist - + Pause Pausar - + Go &offline &Desconectarse - + Go &online &Conectarse - + Authentication Error Error de autenticación - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 por %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Acerca de Tomahawk @@ -3278,47 +3283,32 @@ introduzca su número PIN aquí:
    Formulario - + Cover Portada - + Track Tema - - by - de - - - + Artist Artista - - from - en - - - + Album Álbum - + Statistics Estadísticas - - Lyrics - - - - + Similar Tracks Temas Similares @@ -3328,27 +3318,27 @@ introduzca su número PIN aquí:
    - + You've listened to this track %n time(s). Ha escuchado esta canción %n vez.Ha escuchado esta canción %n veces. - + You've never listened to this track before. Nunca ha escuchado este tema antes. - + You first listened to it on %1. Escuchó este tema pro primera vez en %1. - + You've listened to %1 %n time(s). Ha escuchado %1 %n vez.Ha escuchado %1 %n veces. - + You've never listened to %1 before. Nunca ha escuchado %1 antes. diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 35160f18f..ba5d41bd0 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -171,32 +171,37 @@ se connecter et streamer depuis chez vous ? Form - + Top Hits Top Hits - + Related Artists Artistes similaires - + Albums Albums - + + Cover + + + + Sorry, we could not find any albums for this artist! Désolé, on a pas pu trouver aucun album pour cet artiste! - + Sorry, we could not find any related artists! Désolé, on a rien trouvé par rapport a cet artite! - + Sorry, we could not find any top hits for this artist! Désolé, on a pas pu trouver aucun top hit pour cet artiste! @@ -1089,17 +1094,17 @@ se connecter et streamer depuis chez vous ?
    Tweet - + Tweet Listening to "%1" by %2. %3 - + J'écoute "%1" par %2. %3 Listening to "%1" by %2 on "%3". %4 - + J'écoute "%1" par %2 sur "%3". %4 @@ -3011,7 +3016,7 @@ saisissez le numéro PIN ici :
    - + Play Lecture @@ -3031,172 +3036,172 @@ saisissez le numéro PIN ici : Suivant - + Back Retour - + Go back one page Reculer d'une page - + Forward Avancer - + Go forward one page Avancer d'une page - + Global Search... Recherche Globale... - - + + Check For Updates... Rechercher une mise à jour... - - - + + + Connect To Peer Connexion à un pair - + Enter peer address: Adresse du pair : - + Enter peer port: Port du pair : - + Enter peer key: Clé du pair : - + XSPF Error Erreur XSPF - + This is not a valid XSPF playlist. Ceci n'est pas une liste de lecture XSPF valide. - + Failed to save tracks Échec de la sauvegarde des pistes - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Certaines pistes dans la liste de lecture ne contiennent pas d'artiste ou de titre. Elles seront ignorées. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sautée. Vérifiez que vous avez un backend Phonon et les plugins requis installés. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Désolé, il y a un problème d'accès à votre matériel audio ou la piste en cours va être sauter. - + Station Station - + Create New Station Créer une nouvelle station - + Name: Nom : - + Playlist Liste de lecture - + Automatic Playlist Liste de lecture automatique - + Pause Pause - + Go &offline Se &déconnecter - + Go &online Se c&onnecter - + Authentication Error Erreur d'authentification - + Error connecting to SIP: Authentication failed! Erreur de connexion SIP : échec de l'authentification ! - + %1 by %2 track, artist name %1 par %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Droit d'auteur 2010 - 2012 - + Thanks to: Merci a: - + About Tomahawk A propos de Tomahawk @@ -3280,47 +3285,32 @@ saisissez le numéro PIN ici : Form - + Cover Pochette - + Track Piste - - by - par - - - + Artist Artiste - - from - de - - - + Album Album - + Statistics Statistiques - - Lyrics - Paroles - - - + Similar Tracks Piste similaire @@ -3330,27 +3320,27 @@ saisissez le numéro PIN ici : Désolé, on a pas pu trouver aucune pistes pour cette chanson! - + You've listened to this track %n time(s). Vous avez écouté cette piste %n fois.Vous avez écouté cette piste %n fois. - + You've never listened to this track before. Vous n'avez encore jamais écouté cette piste. - + You first listened to it on %1. Vous l'avez écouté pour la première fois le %1. - + You've listened to %1 %n time(s). Vous avez écouté %1 %n fois.Vous avez écouté %1 %n fois. - + You've never listened to %1 before. Vous n'avez encore jamais écouté %1. diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index a07497888..421954157 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -170,32 +170,37 @@ connect and stream from you? フォーム - + Top Hits 大ヒット曲 - + Related Artists 似たアーティスト - + Albums アルバム - + + Cover + + + + Sorry, we could not find any albums for this artist! このアーティストのアルバムは見つかりませんでした。 - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3001,7 +3006,7 @@ Meta+Ctrl+Z - + Play 再生 @@ -3021,172 +3026,172 @@ Meta+Ctrl+Z 次へ - + Back プレイリスト - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station ステーション - + Create New Station 新規ステーションを作成 - + Name: 名前: - + Playlist プレイリスト - + Automatic Playlist - + Pause 一時停止 - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 by %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 Copyright 2010 - 2012 - + Thanks to: Thanks to: - + About Tomahawk Tomahawkについて @@ -3270,47 +3275,32 @@ Meta+Ctrl+Z フォーム - + Cover カバー - + Track トラック - - by - by - - - + Artist アーティスト - - from - from - - - + Album アルバム - + Statistics 統計 - - Lyrics - 歌詞 - - - + Similar Tracks 似ているトラック @@ -3320,27 +3310,27 @@ Meta+Ctrl+Z この曲に似ているトラックが見つかりませんでした。 - + You've listened to this track %n time(s). このトラックは%n回聴いています。 - + You've never listened to this track before. このトラックを一度も聴いていません。 - + You first listened to it on %1. 初めてこの曲を聴いたのは、%1です。 - + You've listened to %1 %n time(s). %1を%n回聴いています。 - + You've never listened to %1 before. %1を一度も聴いていません。 diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index d186416b5..483f8596b 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -170,32 +170,37 @@ connect and stream from you? Formularz - + Top Hits Hity na Topie - + Related Artists Powiązani artyści - + Albums Albumy - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3005,7 +3010,7 @@ wprowadź pokazany numer PIN tutaj: - + Play Odtwarzaj @@ -3025,172 +3030,172 @@ wprowadź pokazany numer PIN tutaj: Następny - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Globalne Wyszukiwanie... - - + + Check For Updates... Sprawdź uaktualnienia... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error Błąd XSPF - + This is not a valid XSPF playlist. To nie jest poprawna lista XSPF. - + Failed to save tracks Nie udało się zapisać utworów - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Niektóre utwory na liście nie zawierają artysty i tytułu. Zostaną one zignorowane. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station Utwórz Nową Stację - + Name: Nazwa: - + Playlist - + Automatic Playlist - + Pause Pauza - + Go &offline Przejdź do trybu &offline - + Go &online Przejdź do trybu &online - + Authentication Error Błąd uwierzytelniania - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 wykonawcy %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3274,47 +3279,32 @@ wprowadź pokazany numer PIN tutaj: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3324,27 +3314,27 @@ wprowadź pokazany numer PIN tutaj: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index fb9c3beb1..69c407f27 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -170,32 +170,37 @@ connect and stream from you? Formulário - + Top Hits Maiores sucessos - + Related Artists Artistas relacionados - + Albums Álbuns - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3004,7 +3009,7 @@ colocar o número PIN mostrado aqui: - + Play Reporduzir @@ -3024,172 +3029,172 @@ colocar o número PIN mostrado aqui: Próximo - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Busca global... - - + + Check For Updates... Buscar atualizações... - - - + + + Connect To Peer Conectar-se ao par - + Enter peer address: Coloque o endereço do par: - + Enter peer port: Coloque a porta do par: - + Enter peer key: Coloque a chave do par: - + XSPF Error Erro de XSPF - + This is not a valid XSPF playlist. Esta não é uma lista de reprodução XSPF válida. - + Failed to save tracks Falha ao salvar faixas - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Algumas faixas da lista de reprodução não contem artista e título. Estas serão ignoradas. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station Criar uma nova estação - + Name: Nome: - + Playlist - + Automatic Playlist - + Pause Pausar - + Go &offline Desc&onectar - + Go &online C&onectar - + Authentication Error Erro de autenticação - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 de %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk Sobre o Tomahawk @@ -3273,47 +3278,32 @@ colocar o número PIN mostrado aqui: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3323,27 +3313,27 @@ colocar o número PIN mostrado aqui: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 595661493..e0f3592a8 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -171,32 +171,37 @@ connect and stream from you? Форма - + Top Hits Хиты - + Related Artists Похожие исполнители - + Albums Альбомы - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -3005,7 +3010,7 @@ enter the displayed PIN number here: - + Play Играть @@ -3025,172 +3030,172 @@ enter the displayed PIN number here: Следующая - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Глобальный поиск - - + + Check For Updates... Проверить обновления... - - - + + + Connect To Peer Связаться с Peer - + Enter peer address: Введите адрес узла: - + Enter peer port: Введите адрес порта: - + Enter peer key: Введите адрес ключа: - + XSPF Error Ошибка XSPF - + This is not a valid XSPF playlist. Это не является допустимым XSPF плейлистом. - + Failed to save tracks Не удалось сохранить песни - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Некоторые треки в плейлисте не содержат исполнителя и название. Они будут проигнорированы. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station Создать новую станцию - + Name: Имя: - + Playlist - + Automatic Playlist - + Pause Пауза - + Go &offline Отключиться - + Go &online Подлючиться - + Authentication Error Ошибка авторизации - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk О Tomahawk @@ -3274,47 +3279,32 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3324,27 +3314,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 11ce88dff..c68912087 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -170,32 +170,37 @@ connect and stream from you? Formulär - + Top Hits Största hits - + Related Artists Relaterade artister - + Albums Album - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -2999,7 +3004,7 @@ enter the displayed PIN number here: - + Play Spela upp @@ -3019,172 +3024,172 @@ enter the displayed PIN number here: Nästa - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... Global sökning... - - + + Check For Updates... Leta efter uppdateringar... - - - + + + Connect To Peer Anslut till klient - + Enter peer address: Ange klientadress: - + Enter peer port: Ange klientport: - + Enter peer key: Ange klientnyckel: - + XSPF Error XSPF-fel - + This is not a valid XSPF playlist. Detta är inte en giltig XSPF-spellista. - + Failed to save tracks Misslyckades med att spara spår - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. Några spår i spellistan innehåller inte någon artist och titel. De kommer att ignoreras. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station Skapa ny station - + Name: Namn: - + Playlist - + Automatic Playlist - + Pause Paus - + Go &offline Koppla &från - + Go &online A&nslut - + Authentication Error Autentiseringsfel - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name %1 av %2 - + %1 - %2 current track, some window title %1 - %2 - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3268,47 +3273,32 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3318,27 +3308,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index a01a24047..98e148293 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -170,32 +170,37 @@ connect and stream from you? Form - + Top Hits En Çok Dinlenenler - + Related Artists Benzer Sanatçılar - + Albums Albümler - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -2998,7 +3003,7 @@ enter the displayed PIN number here: - + Play @@ -3018,172 +3023,172 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station - + Name: - + Playlist - + Automatic Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3267,47 +3272,32 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3317,27 +3307,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 50626f41a..d8de2daf9 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -170,32 +170,37 @@ connect and stream from you? - + Top Hits 最热曲目 - + Related Artists 相关艺人 - + Albums 专辑 - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -2998,7 +3003,7 @@ enter the displayed PIN number here: - + Play @@ -3018,172 +3023,172 @@ enter the displayed PIN number here: - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station - + Name: - + Playlist - + Automatic Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3267,47 +3272,32 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3317,27 +3307,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 347560dac..d23368dc2 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -170,32 +170,37 @@ connect and stream from you? 形式 - + Top Hits 流行精選 - + Related Artists 相關演出者 - + Albums 專輯 - + + Cover + + + + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -2998,7 +3003,7 @@ enter the displayed PIN number here: - + Play 播放 @@ -3018,172 +3023,172 @@ enter the displayed PIN number here: 下一首 - + Back - + Go back one page - + Forward - + Go forward one page - + Global Search... 全域搜尋... - - + + Check For Updates... 檢查更新... - - - + + + Connect To Peer 連接點對點 - + Enter peer address: 輸入對等地址: - + Enter peer port: 輸入對等連接埠: - + Enter peer key: 輸入對等密鑰: - + XSPF Error XSPF 錯誤 - + This is not a valid XSPF playlist. - + Failed to save tracks 無法儲存曲目 - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - + Station - + Create New Station - + Name: 名稱: - + Playlist - + Automatic Playlist - + Pause 暫停 - + Go &offline 離線 - + Go &online 上網 - + Authentication Error 驗證錯誤 - + Error connecting to SIP: Authentication failed! - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + <h2><b>Tomahawk %1<br/>(%2)</h2> <h2><b>Tomahawk %1<br/>(%2)</h2> - + <h2><b>Tomahawk %1</h2> <h2><b>Tomahawk %1</h2> - + Copyright 2010 - 2012 - + Thanks to: - + About Tomahawk @@ -3267,47 +3272,32 @@ enter the displayed PIN number here: - + Cover - + Track - - by - - - - + Artist - - from - - - - + Album - + Statistics - - Lyrics - - - - + Similar Tracks @@ -3317,27 +3307,27 @@ enter the displayed PIN number here: - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. From ab5fe146d4cf9c3e5c50aac1bc3aa7b219951243 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 07:32:09 +0200 Subject: [PATCH 403/433] * Swap Albums & Related Artists. --- .../widgets/infowidgets/ArtistInfoWidget.ui | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui index d56a38610..ba975d2d0 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.ui @@ -60,6 +60,40 @@ + + + + + Arial + 20 + 75 + true + + + + Albums + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 190 + + + + @@ -94,41 +128,6 @@ - - - - - Arial - 20 - 75 - true - true - - - - Albums - - - 0 - - - - - - - - 0 - 0 - - - - - 0 - 190 - - - - From e831ba9c46ec5276ad838116c70f99a76f0307ca Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 07:32:27 +0200 Subject: [PATCH 404/433] * Fixed typo in SeekSlider. --- src/libtomahawk/widgets/SeekSlider.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/widgets/SeekSlider.cpp b/src/libtomahawk/widgets/SeekSlider.cpp index 9a03f5c62..f956a5a70 100644 --- a/src/libtomahawk/widgets/SeekSlider.cpp +++ b/src/libtomahawk/widgets/SeekSlider.cpp @@ -31,7 +31,7 @@ SeekSlider::SeekSlider( QWidget* parent ) , m_timeLine( 0 ) { setFixedHeight( 20 ); - setStyleSheet( "QSlider::groove::horizontal {" + setStyleSheet( "QSlider::groove:horizontal {" "margin: 5px; border-width: 3px;" "border-image: url(" RESPATH "images/seek-slider-bkg.png) 3 3 3 3 stretch stretch;" "}" @@ -41,7 +41,7 @@ SeekSlider::SeekSlider( QWidget* parent ) "border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;" "}" - "QSlider::handle::horizontal {" + "QSlider::handle:horizontal {" "margin-bottom: -7px; margin-top: -7px;" "margin-left: -4px; margin-right: -4px;" "height: 17px; width: 16px;" From 9bea6b8709a1438e5b4a3c56bba9342aaece0324 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 07:32:51 +0200 Subject: [PATCH 405/433] * Added scrollbar border-images. --- data/images/scrollbar-horizontal-handle.png | Bin 0 -> 397 bytes data/images/scrollbar-vertical-handle.png | Bin 0 -> 376 bytes resources.qrc | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 data/images/scrollbar-horizontal-handle.png create mode 100644 data/images/scrollbar-vertical-handle.png diff --git a/data/images/scrollbar-horizontal-handle.png b/data/images/scrollbar-horizontal-handle.png new file mode 100644 index 0000000000000000000000000000000000000000..3589d64a4d7cc6d48dfa0bd1274451471f9ce5c4 GIT binary patch literal 397 zcmV;80doF{P)>nu(L4PVFvtXeQa23$Tt6%{FwnB%@kkWFla>x zAtz!S$D?a4V}jfvH%N*Mv37cg%SH%U06iNw$Pe;{JVQ+Vp}-jP5JI@cG~V4;Qh%pxgb=be r@s#Zy*~*Sg>Hq%$5JJeQ_!VFP$Z=bQEkQr_00000NkvXXu0mjfAQ`1_ literal 0 HcmV?d00001 diff --git a/data/images/scrollbar-vertical-handle.png b/data/images/scrollbar-vertical-handle.png new file mode 100644 index 0000000000000000000000000000000000000000..2676d365dc0116884758066249bbdf99aec026d2 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^oD2+%DjaM;*551AK0u14*vT`50|;t3QaV5i3Opi< z85sDEfH31!Z9ZwB4k=F;$B>N1x3?Vq4jTxxKD00N6*)0Yxqw|u?52Qb_nqeC1EvBo z%GH}*%UU>X>gnRjYG>s$%50E((3=wZsm6HIUb!data/misc/tomahawk_pubkey.pem data/images/track-icon-sidebar.png data/images/jump-link.png + data/images/scrollbar-vertical-handle.png + data/images/scrollbar-horizontal-handle.png From c99df9257cba596a5e02c685133c47576a574a12 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 07:33:16 +0200 Subject: [PATCH 406/433] * Added custom scrollbars for testing. --- .../widgets/infowidgets/ArtistInfoWidget.cpp | 14 ++++++++++++++ .../widgets/infowidgets/TrackInfoWidget.cpp | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 8732596c0..918678473 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -22,6 +22,7 @@ #include "ui_ArtistInfoWidget.h" #include +#include #include "audio/AudioEngine.h" #include "playlist/PlayableModel.h" @@ -127,6 +128,19 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* setLayout( layout ); TomahawkUtils::unmarginLayout( layout ); + QString scrollBarStyleSheet( + "QScrollBar:horizontal { background-color: transparent; }" + "QScrollBar::handle:horizontal { border-height: 9px; margin-bottom: 6px;" + "border-image: url(" RESPATH "images/scrollbar-horizontal-handle.png) 3 3 3 3 stretch stretch;" + "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" + "QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { width: 0px; height: 0px; background: none; }" + "QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; height: 0px; background: none; }" + "QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {" + "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" ); + + ui->albums->horizontalScrollBar()->setStyleSheet( scrollBarStyleSheet ); + ui->relatedArtists->horizontalScrollBar()->setStyleSheet( scrollBarStyleSheet ); + load( artist ); } diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 3364575b4..87e96e4cd 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -22,6 +22,7 @@ #include "ui_TrackInfoWidget.h" #include +#include #include "ViewManager.h" #include "SourceList.h" @@ -58,6 +59,16 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->lyricsView->setFrameShape( QFrame::NoFrame ); ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + ui->similarTracksView->verticalScrollBar()->setStyleSheet( + "QScrollBar:vertical { background-color: transparent; }" + "QScrollBar::handle:vertical { border-width: 9px; margin-right: 6px;" + "border-image: url(" RESPATH "images/scrollbar-vertical-handle.png) 3 3 3 3 stretch stretch;" + "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" + "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { width: 0px; height: 0px; background: none; }" + "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { width: 0px; height: 0px; background: none; }" + "QScrollBar:up-arrow:vertical, QScrollBar::down-arrow:vertical {" + "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" ); + QFont f = font(); f.setBold( true ); f.setPixelSize( 18 ); From d4dff8809a5cc5a1868acedd3c543c511a517499 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 08:44:36 +0200 Subject: [PATCH 407/433] * Added styleScrollBar method to TomahawkUtils. --- src/libtomahawk/utils/TomahawkUtilsGui.cpp | 25 ++++++++++++++++++++++ src/libtomahawk/utils/TomahawkUtilsGui.h | 4 +++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index ccf8cdf2c..9a814a3e5 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -441,4 +442,28 @@ prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, Pl } } + +void +styleScrollBar( QScrollBar* scrollBar ) +{ + scrollBar->setStyleSheet( + "QScrollBar:horizontal { background-color: transparent; }" + "QScrollBar::handle:horizontal { border-height: 9px; margin-bottom: 6px;" + "border-image: url(" RESPATH "images/scrollbar-horizontal-handle.png) 3 3 3 3 stretch stretch;" + "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" + "QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { width: 0px; height: 0px; background: none; }" + "QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; height: 0px; background: none; }" + "QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {" + "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" + + "QScrollBar:vertical { background-color: transparent; }" + "QScrollBar::handle:vertical { border-width: 9px; margin-right: 6px;" + "border-image: url(" RESPATH "images/scrollbar-vertical-handle.png) 3 3 3 3 stretch stretch;" + "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" + "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { width: 0px; height: 0px; background: none; }" + "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { width: 0px; height: 0px; background: none; }" + "QScrollBar:up-arrow:vertical, QScrollBar::down-arrow:vertical {" + "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" ); +} + } // ns diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.h b/src/libtomahawk/utils/TomahawkUtilsGui.h index 1c89f8bce..df89d9bc8 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.h +++ b/src/libtomahawk/utils/TomahawkUtilsGui.h @@ -35,6 +35,7 @@ class QPixmap; class QLayout; class QPalette; class QRect; +class QScrollBar; namespace TomahawkUtils { @@ -59,7 +60,8 @@ namespace TomahawkUtils DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode = TomahawkUtils::Original, const QSize& size = QSize( 0, 0 ) ); DLLEXPORT void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ); - + + DLLEXPORT void styleScrollBar( QScrollBar* scrollBar ); } #endif // TOMAHAWKUTILSGUI_H From 6c725e72e72070f817644d34b56d7326f4d31269 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 08:44:56 +0200 Subject: [PATCH 408/433] * Use styleScrollBar method. --- .../widgets/infowidgets/ArtistInfoWidget.cpp | 14 ++------------ .../widgets/infowidgets/TrackInfoWidget.cpp | 11 ++--------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 918678473..f2222479b 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -128,18 +128,8 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* setLayout( layout ); TomahawkUtils::unmarginLayout( layout ); - QString scrollBarStyleSheet( - "QScrollBar:horizontal { background-color: transparent; }" - "QScrollBar::handle:horizontal { border-height: 9px; margin-bottom: 6px;" - "border-image: url(" RESPATH "images/scrollbar-horizontal-handle.png) 3 3 3 3 stretch stretch;" - "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" - "QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { width: 0px; height: 0px; background: none; }" - "QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0px; height: 0px; background: none; }" - "QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {" - "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" ); - - ui->albums->horizontalScrollBar()->setStyleSheet( scrollBarStyleSheet ); - ui->relatedArtists->horizontalScrollBar()->setStyleSheet( scrollBarStyleSheet ); + TomahawkUtils::styleScrollBar( ui->albums->horizontalScrollBar() ); + TomahawkUtils::styleScrollBar( ui->relatedArtists->horizontalScrollBar() ); load( artist ); } diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 87e96e4cd..3cf70a51f 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -59,15 +59,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->lyricsView->setFrameShape( QFrame::NoFrame ); ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - ui->similarTracksView->verticalScrollBar()->setStyleSheet( - "QScrollBar:vertical { background-color: transparent; }" - "QScrollBar::handle:vertical { border-width: 9px; margin-right: 6px;" - "border-image: url(" RESPATH "images/scrollbar-vertical-handle.png) 3 3 3 3 stretch stretch;" - "border-top: 3px transparent; border-bottom: 3px transparent; border-right: 3px transparent; border-left: 3px transparent; }" - "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { width: 0px; height: 0px; background: none; }" - "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { width: 0px; height: 0px; background: none; }" - "QScrollBar:up-arrow:vertical, QScrollBar::down-arrow:vertical {" - "border: 0px; width: 0px; height: 0px; background: none; background-color: transparent; }" ); + TomahawkUtils::styleScrollBar( ui->similarTracksView->verticalScrollBar() ); + TomahawkUtils::styleScrollBar( ui->lyricsView->verticalScrollBar() ); QFont f = font(); f.setBold( true ); From a512d85672cd11ab1ee538a2f1ee5af9725928db Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 08:47:15 +0200 Subject: [PATCH 409/433] * Fixed accidental dupe connect. --- src/libtomahawk/playlist/GridView.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/playlist/GridView.cpp b/src/libtomahawk/playlist/GridView.cpp index 62209e3d5..35eeb558a 100644 --- a/src/libtomahawk/playlist/GridView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -81,7 +81,6 @@ GridView::GridView( QWidget* parent ) connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); - connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) ); connect( proxyModel(), SIGNAL( modelReset() ), SLOT( layoutItems() ) ); // connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); } From a1874a941d77da61d48c8e59e7f373f5938087c9 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 09:20:41 +0200 Subject: [PATCH 410/433] Sort new releases by date, show newest release first. --- .../generic/newreleases/NewReleasesPlugin.cpp | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp b/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp index 54910bf49..b5b2ae1a2 100644 --- a/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp +++ b/src/infoplugins/generic/newreleases/NewReleasesPlugin.cpp @@ -24,6 +24,20 @@ using namespace Tomahawk::InfoSystem; +bool newReleaseSort( const InfoStringHash& left, const InfoStringHash& right ) +{ + if ( !left.contains( "date" ) || !right.contains( "date" ) ) + { + return true; + } + + const QDate lDate = QDate::fromString( left[ "date" ], "yyyy-MM-dd" ); + const QDate rDate = QDate::fromString( right[ "date" ], "yyyy-MM-dd" ); + + return lDate > rDate; +} + + NewReleasesPlugin::NewReleasesPlugin() : InfoPlugin() , m_nrFetchJobs ( 0 ) @@ -274,6 +288,7 @@ void NewReleasesPlugin::nrList() } } + if ( !albumNRs.isEmpty() ) newreleases.insert ( tr ( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > > ( albumNRs ) ); @@ -334,11 +349,14 @@ void NewReleasesPlugin::nrReturned() Tomahawk::InfoSystem::InfoStringHash pair; pair["artist"] = artist; pair["album"] = album; + pair["date"] = date; newreleases.append( pair ); } } - tDebug() << "NewReleasesPlugin:" << "\tgot " << newreleases.size() << " albums"; + qSort( newreleases.begin(), newreleases.end(), newReleaseSort ); + +// tDebug() << "NewReleasesPlugin:" << "\tgot " << newreleases.size() << " albums"; returnedData[ "albums" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( newreleases ); returnedData[ "type" ] = "albums"; Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(); From c2363e09675e43f7e865e8e131cf738af2bfdd7c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 23 May 2012 09:35:25 -0400 Subject: [PATCH 411/433] Enable stage playlist exporting rename --- src/libtomahawk/GlobalActionManager.cpp | 7 +++++++ src/sourcetree/SourceTreeView.cpp | 10 ++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/GlobalActionManager.cpp b/src/libtomahawk/GlobalActionManager.cpp index 4fca818b1..e1ddf7e63 100644 --- a/src/libtomahawk/GlobalActionManager.cpp +++ b/src/libtomahawk/GlobalActionManager.cpp @@ -1233,6 +1233,13 @@ GlobalActionManager::waitingForResolved( bool /* success */ ) } +QString +GlobalActionManager::hostname() const +{ + return QString( "http://stage.toma.hk" ); +} + + /// SPOTIFY URL HANDLING bool diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index fb2dfbd7b..55134566f 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -227,7 +227,7 @@ SourceTreeView::setupMenus() } if ( type == SourcesModel::StaticPlaylist ) - copyPlaylistAction->setText( tr( "&Export Playlist" ) ); + copyPlaylistAction->setText( tr( "&Copy Playlist Link" ) ); connect( loadPlaylistAction, SIGNAL( triggered() ), SLOT( loadPlaylist() ) ); connect( renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) ); @@ -398,8 +398,10 @@ SourceTreeView::copyPlaylistLink() else if ( type == SourcesModel::StaticPlaylist ) { // Disable toma.hk playlist mode until ready - // GlobalActionManager::instance()->getShortLink( playlist ); - + PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); + playlist_ptr playlist = item->playlist(); + GlobalActionManager::instance()->getShortLink( playlist ); +/* PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); playlist_ptr playlist = item->playlist(); @@ -411,7 +413,7 @@ SourceTreeView::copyPlaylistLink() QFileInfo playlistAbsoluteFilePath = filename; TomahawkSettings::instance()->setPlaylistDefaultPath( playlistAbsoluteFilePath.absolutePath() ); GlobalActionManager::instance()->savePlaylistToFile( playlist, filename ); - } + } */ } } From 5b98bc9c752de01a6f423f133d67a9f0bfcc464c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 17:09:13 +0200 Subject: [PATCH 412/433] Style and fix merge --- src/libtomahawk/GlobalActionManager.cpp | 9 +-------- src/sourcetree/SourceTreeView.cpp | 1 + 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/GlobalActionManager.cpp b/src/libtomahawk/GlobalActionManager.cpp index e1ddf7e63..c2904df07 100644 --- a/src/libtomahawk/GlobalActionManager.cpp +++ b/src/libtomahawk/GlobalActionManager.cpp @@ -166,7 +166,7 @@ GlobalActionManager::getShortLink( const playlist_ptr& pl ) // No built-in Qt facilities for doing a FORM POST. So we build the payload ourselves... const QByteArray boundary = "----------------------------2434992cccab"; - QByteArray data(QByteArray("--" + boundary + "\r\n")); + QByteArray data( QByteArray( "--" + boundary + "\r\n" ) ); data += "Content-Disposition: form-data; name=\"data\"; filename=\"playlist.jspf\"\r\n"; data += "Content-Type: application/octet-stream\r\n\r\n"; data += msg; @@ -1233,13 +1233,6 @@ GlobalActionManager::waitingForResolved( bool /* success */ ) } -QString -GlobalActionManager::hostname() const -{ - return QString( "http://stage.toma.hk" ); -} - - /// SPOTIFY URL HANDLING bool diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index 55134566f..6316407e3 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell + * Copyright 2010-2012, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 26733aa85f86293a35058404530615a45f951633 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 17:09:38 +0200 Subject: [PATCH 413/433] Add a Copy Link action and keep Export Playlist for static playlists --- src/sourcetree/SourceTreeView.cpp | 56 ++++++++++++++++++++----------- src/sourcetree/SourceTreeView.h | 1 + 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index 6316407e3..b56185cc1 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -190,6 +190,13 @@ SourceTreeView::setupMenus() m_playlistMenu.addSeparator(); QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); + + if ( type == SourcesModel::StaticPlaylist ) + { + QAction* exportPlaylist = m_playlistMenu.addAction( tr( "&Export Playlist") ); + connect( exportPlaylist, SIGNAL( triggered() ), this, SLOT( exportPlaylist() ) ); + } + QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); QString addToText; @@ -227,9 +234,6 @@ SourceTreeView::setupMenus() } } - if ( type == SourcesModel::StaticPlaylist ) - copyPlaylistAction->setText( tr( "&Copy Playlist Link" ) ); - connect( loadPlaylistAction, SIGNAL( triggered() ), SLOT( loadPlaylist() ) ); connect( renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) ); connect( deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) ); @@ -398,23 +402,37 @@ SourceTreeView::copyPlaylistLink() } else if ( type == SourcesModel::StaticPlaylist ) { - // Disable toma.hk playlist mode until ready - PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); - playlist_ptr playlist = item->playlist(); - GlobalActionManager::instance()->getShortLink( playlist ); -/* - PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); - playlist_ptr playlist = item->playlist(); + const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); + const playlist_ptr playlist = item->playlist(); - QString suggestedFilename = TomahawkSettings::instance()->playlistDefaultPath() + "/" + playlist->title(); - QString filename = QFileDialog::getSaveFileName( TomahawkUtils::tomahawkWindow(), tr( "Save XSPF" ), - suggestedFilename, tr( "Playlists (*.xspf)" ) ); - if ( !filename.isEmpty() ) - { - QFileInfo playlistAbsoluteFilePath = filename; - TomahawkSettings::instance()->setPlaylistDefaultPath( playlistAbsoluteFilePath.absolutePath() ); - GlobalActionManager::instance()->savePlaylistToFile( playlist, filename ); - } */ + GlobalActionManager::instance()->getShortLink( playlist ); + } +} + + +void +SourceTreeView::exportPlaylist() +{ + const QModelIndex idx = m_contextMenuIndex; + if ( !idx.isValid() ) + return; + + const SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); + Q_ASSERT( type == SourcesModel::StaticPlaylist ); + if ( type != SourcesModel::StaticPlaylist ) + return; + + const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); + const playlist_ptr playlist = item->playlist(); + + const QString suggestedFilename = TomahawkSettings::instance()->playlistDefaultPath() + "/" + playlist->title(); + const QString filename = QFileDialog::getSaveFileName( TomahawkUtils::tomahawkWindow(), tr( "Save XSPF" ), + suggestedFilename, tr( "Playlists (*.xspf)" ) ); + if ( !filename.isEmpty() ) + { + const QFileInfo playlistAbsoluteFilePath( filename ); + TomahawkSettings::instance()->setPlaylistDefaultPath( playlistAbsoluteFilePath.absolutePath() ); + GlobalActionManager::instance()->savePlaylistToFile( playlist, filename ); } } diff --git a/src/sourcetree/SourceTreeView.h b/src/sourcetree/SourceTreeView.h index 388649d3c..775ecb62b 100644 --- a/src/sourcetree/SourceTreeView.h +++ b/src/sourcetree/SourceTreeView.h @@ -72,6 +72,7 @@ private slots: void loadPlaylist(); void deletePlaylist( const QModelIndex& = QModelIndex() ); void copyPlaylistLink(); + void exportPlaylist(); void addToLocal(); void latchOnOrCatchUp(); From bb571081824039116f30ad68e2ed15379ba09896 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 20:56:19 +0200 Subject: [PATCH 414/433] Set account friendly name for spotify account --- src/libtomahawk/TomahawkSettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index 01a794749..95414de1a 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -191,6 +191,7 @@ TomahawkSettings::createSpotifyAccount() setValue( "types", QStringList() << "ResolverType" ); setValue( "credentials", QVariantHash() ); setValue( "configuration", QVariantHash() ); + setValue( "accountfriendlyname", "Spotify" ); endGroup(); QStringList allAccounts = value( "accounts/allaccounts" ).toStringList(); From 6d79fc2ab8e89e767e729fd01f51a224bfee5243 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 20:56:59 +0200 Subject: [PATCH 415/433] Set friendly name for spotify account to prevent the dupe check from deleting it --- src/libtomahawk/TomahawkSettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index 95414de1a..cab903074 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -484,6 +484,7 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) setValue( "enabled", enabled ); setValue( "autoconnect", autoconnect ); setValue( "types", QStringList() << "ResolverType" ); + setValue( "accountfriendlyname", "Spotify" ); setValue( "configuration", configuration ); endGroup(); From 96d89e230c55576570124e9baf23c9174db6d3f7 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 20:57:17 +0200 Subject: [PATCH 416/433] Uncomment out some migration code :) --- src/libtomahawk/TomahawkSettings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index cab903074..654a7e2b2 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -558,10 +558,10 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) } endGroup(); - -// setPlaylistUpdaters( updaters ); - remove( "playlistupdaters" ); + + setValue( "playlists/updaters", QVariant::fromValue< SerializedUpdaters >( updaters ) ); + } else if ( oldVersion == 11 ) { From c41c7eaa94d3e834d9612c503718e5ae3923427f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 14 Jun 2012 21:21:58 +0200 Subject: [PATCH 417/433] Provide base64 encode and decode to js resolvers --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 14 ++++++++++++++ src/libtomahawk/resolvers/QtScriptResolver.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 1bfa4ea5e..d20d411eb 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -176,6 +176,20 @@ QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QStr } +QByteArray +QtScriptResolverHelper::base64Encode( const QByteArray& input ) +{ + return input.toBase64(); +} + + +QByteArray +QtScriptResolverHelper::base64Decode( const QByteArray& input ) +{ + return QByteArray::fromBase64( input ); +} + + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 85d10d59e..c2dae5210 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -53,6 +53,9 @@ public: Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ); + Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); + Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); + QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); public slots: From 7abd653b31023a0e68f602e331f7f992a763905c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 11:21:42 +0200 Subject: [PATCH 418/433] * Style cleanup. --- src/sourcetree/SourceTreeView.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index b56185cc1..3e961441b 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -171,11 +171,11 @@ SourceTreeView::setupMenus() { if ( m_latchManager->isLatched( source ) ) { - QAction *latchOffAction = ActionCollection::instance()->getAction( "latchOff" ); + QAction* latchOffAction = ActionCollection::instance()->getAction( "latchOff" ); m_latchMenu.addAction( latchOffAction ); connect( latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) ); m_latchMenu.addSeparator(); - QAction *latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" ); + QAction* latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" ); latchRealtimeAction->setChecked( source->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime ); m_latchMenu.addAction( latchRealtimeAction ); connect( latchRealtimeAction, SIGNAL( toggled( bool ) ), SLOT( latchModeToggled( bool ) ) ); @@ -183,13 +183,13 @@ SourceTreeView::setupMenus() } } - QAction *loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" ); + QAction* loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" ); m_playlistMenu.addAction( loadPlaylistAction ); - QAction *renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" ); + QAction* renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" ); m_playlistMenu.addAction( renamePlaylistAction ); m_playlistMenu.addSeparator(); - QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); + QAction* copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); if ( type == SourcesModel::StaticPlaylist ) { @@ -197,7 +197,7 @@ SourceTreeView::setupMenus() connect( exportPlaylist, SIGNAL( triggered() ), this, SLOT( exportPlaylist() ) ); } - QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); + QAction* deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); QString addToText; if ( type == SourcesModel::StaticPlaylist ) @@ -207,7 +207,7 @@ SourceTreeView::setupMenus() else if ( type == SourcesModel::Station ) addToText = tr( "Add to my Stations" ); - QAction *addToLocalAction = m_roPlaylistMenu.addAction( addToText ); + QAction* addToLocalAction = m_roPlaylistMenu.addAction( addToText ); m_roPlaylistMenu.addAction( copyPlaylistAction ); deletePlaylistAction->setEnabled( !readonly ); @@ -703,7 +703,7 @@ SourceTreeView::dropEvent( QDropEvent* event ) if ( DropJob::isDropType( DropJob::Playlist, event->mimeData() ) ) { qDebug() << Q_FUNC_INFO << "Current Event"; - DropJob *dropThis = new DropJob; + DropJob* dropThis = new DropJob; dropThis->setDropTypes( DropJob::Playlist ); dropThis->setDropAction( DropJob::Create ); dropThis->parseMimeData( event->mimeData() ); @@ -732,7 +732,7 @@ SourceTreeView::dropEvent( QDropEvent* event ) void -SourceTreeView::keyPressEvent( QKeyEvent *event ) +SourceTreeView::keyPressEvent( QKeyEvent* event ) { if ( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !selectionModel()->selectedIndexes().isEmpty() ) { From 848721902c169e207687739548f86b0dc57d9f19 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 21:45:08 +0200 Subject: [PATCH 419/433] * Silly style cleanup. --- src/libtomahawk/GlobalActionManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/GlobalActionManager.cpp b/src/libtomahawk/GlobalActionManager.cpp index c2904df07..0cc4e1cd7 100644 --- a/src/libtomahawk/GlobalActionManager.cpp +++ b/src/libtomahawk/GlobalActionManager.cpp @@ -385,7 +385,7 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url ) tDebug() << "No xspf or jspf to load..."; return false; } - if ( url.hasQueryItem( "xspf") ) + if ( url.hasQueryItem( "xspf" ) ) { QUrl xspf = QUrl::fromUserInput( url.queryItemValue( "xspf" ) ); QString title = url.hasQueryItem( "title" ) ? url.queryItemValue( "title" ) : QString(); From 4fad494630ea66c51c42c123093cbb617474d270 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 21:45:29 +0200 Subject: [PATCH 420/433] * Add PlayableModel::itemSize(). --- src/libtomahawk/playlist/PlayableModel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 2d436c5db..1b864a575 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -115,6 +115,7 @@ public: void updateDetailedInfo( const QModelIndex& index ); + QSize itemSize() const { return m_itemSize; } void setItemSize( const QSize& size ) { m_itemSize = size; } void startLoading(); From 87dd871c6c614e0456f6827ae3b3c5f1b7b70f0d Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 21:46:17 +0200 Subject: [PATCH 421/433] * GridView now supports auto-resizing to fit its contents. --- src/libtomahawk/playlist/GridView.cpp | 8 ++++++++ src/libtomahawk/playlist/GridView.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/libtomahawk/playlist/GridView.cpp b/src/libtomahawk/playlist/GridView.cpp index 35eeb558a..3d935b876 100644 --- a/src/libtomahawk/playlist/GridView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -74,6 +74,7 @@ GridView::GridView( QWidget* parent ) setStyleSheet( "QListView { background-color: #323435; }" ); setAutoFitItems( true ); + setAutoResize( false ); setProxyModel( new PlayableProxyModel( this ) ); /* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) ); @@ -221,6 +222,13 @@ GridView::layoutItems() m_model->setItemSize( QSize( newItemWidth, newItemWidth ) ); + if ( autoResize() ) + { + int rows = ceil( (double)m_proxyModel->rowCount( QModelIndex() ) / (double)itemsPerRow ); + int newHeight = rows * newItemWidth; + setFixedHeight( newHeight ); + } + if ( !m_inited ) { m_inited = true; diff --git a/src/libtomahawk/playlist/GridView.h b/src/libtomahawk/playlist/GridView.h index a69120969..ffb5befa9 100644 --- a/src/libtomahawk/playlist/GridView.h +++ b/src/libtomahawk/playlist/GridView.h @@ -54,6 +54,9 @@ public: bool autoFitItems() const { return m_autoFitItems; } void setAutoFitItems( bool b ) { m_autoFitItems = b; } + bool autoResize() const { return m_autoResize; } + void setAutoResize( bool b ) { m_autoResize = b; } + void setPlayableModel( PlayableModel* model ); void setModel( QAbstractItemModel* model ); @@ -105,6 +108,7 @@ private: QString m_emptyTip; bool m_inited; bool m_autoFitItems; + bool m_autoResize; QRect m_paintRect; }; From 18bd29307431554ba480475286b05b2666106939 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 21:47:15 +0200 Subject: [PATCH 422/433] * Let track page automatically resize. --- src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp index 3cf70a51f..3354b4e19 100644 --- a/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/TrackInfoWidget.cpp @@ -59,6 +59,8 @@ TrackInfoWidget::TrackInfoWidget( const Tomahawk::query_ptr& query, QWidget* par ui->lyricsView->setFrameShape( QFrame::NoFrame ); ui->lyricsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + ui->similarTracksView->setAutoResize( true ); + ui->similarTracksView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); TomahawkUtils::styleScrollBar( ui->similarTracksView->verticalScrollBar() ); TomahawkUtils::styleScrollBar( ui->lyricsView->verticalScrollBar() ); From 7552ef4ccedf3fb9b52dd6f72b6ed3d4edbd8df5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 14 Jun 2012 21:53:58 +0200 Subject: [PATCH 423/433] * Disable queue's tooltip for 0.5. Needs some more fixing. --- src/libtomahawk/playlist/QueueView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/QueueView.cpp b/src/libtomahawk/playlist/QueueView.cpp index 83c1414ba..e939e2b6d 100644 --- a/src/libtomahawk/playlist/QueueView.cpp +++ b/src/libtomahawk/playlist/QueueView.cpp @@ -52,7 +52,8 @@ QueueView::QueueView( AnimatedSplitter* parent ) ui->queue->setPlaylistModel( queueModel ); queueModel->setReadOnly( false ); - ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); +// ui->queue->setEmptyTip( tr( "The queue is currently empty. Drop something to enqueue it!" ) ); + ui->queue->setEmptyTip( QString() ); connect( queueModel, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( updateLabel() ) ); connect( ui->toggleButton, SIGNAL( clicked() ), SLOT( show() ) ); From 2f6b08948adae23d1eab9d02460c555d7933bb36 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Thu, 14 Jun 2012 22:16:50 +0000 Subject: [PATCH 424/433] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_bg.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_ca.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_de.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_en.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_es.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_fr.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_ja.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_pl.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_pt_BR.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_ru.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_sv.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_tr.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_zh_CN.ts | 63 +++++++++++++++++++----------------------- lang/tomahawk_zh_TW.ts | 63 +++++++++++++++++++----------------------- 15 files changed, 435 insertions(+), 510 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 4555445c1..db68a1516 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -176,32 +176,32 @@ connect and stream from you? الأكثر شهرة - + Related Artists الفنانين ذات الذوق القريب - + Albums ألبومات - + Cover - + Sorry, we could not find any albums for this artist! نعتذر, لم نستطيع إيجاد ألبومات أخرى لهذا الفنان! - + Sorry, we could not find any related artists! نعتذر، لم نستطيع إيجاد فنانين! - + Sorry, we could not find any top hits for this artist! نعتذر، لم نستطيع إيجاد أغاني مشهورة جدا لهذا الفنان! @@ -947,22 +947,17 @@ connect and stream from you? - + Open Queue إفتح قائمة الإنتظار - - - The queue is currently empty. Drop something to enqueue it! - قائمة الانتظار هذه فارغة حاليا. إرمي شيئا لإضافته! - - + Open Queue - %n item(s) إفتح قائمة الإنتظار - %n بندإفتح قائمة الإنتظار - بند %nإفتح قائمة الإنتظار - بندين %nإفتح قائمة الإنتظار - %n بنودإفتح قائمة الإنتظار - %n بنودإفتح قائمة الإنتظار - %n بنود - + Close Queue أغلق قائمة الإنتظار @@ -1263,69 +1258,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &نسخ الرابط - + &Delete %1 &أحذف %1 - + Add to my Playlists أضف إلى لوائحي للأغاني - + Add to my Automatic Playlists أضف إلى لوائحي الأوتوماتيكية للأغاني - + Add to my Stations أضف إلى إذاعاتي - + &Export Playlist &تصدير قائمة الأغاني - + playlist قائمة الأغاني - + automatic playlist قائمة أغاني أوتوماتيكية - + station إذاعة - + Delete %1? playlist/station/... أحذف %1؟ - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? هل ترغب في حذف %1 <b>"%2"</b>؟ - + Save XSPF حفظ XSPF - + Playlists (*.xspf) قوائم أغاني (*.xspf) @@ -2628,7 +2623,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums ألبومات @@ -3315,32 +3310,32 @@ enter the displayed PIN number here: أغاني قريبة - + Sorry, but we could not find similar tracks for this song! نعتذر، لم نستطيع إيجاد أغاني قريبة من هذه الأغنية! - + You've listened to this track %n time(s). لقد استمعت إلى هذه الأغنية %n مرة.لقد استمعت إلى هذه الأغنية مرة %n.لقد استمعت إلى هذه الأغنية مرتين %n.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات.لقد استمعت إلى هذه الأغنية %n مرات. - + You've never listened to this track before. لم تستمع لهذه الأغنية من قبل. - + You first listened to it on %1. استمعت إليها أولاً في %1. - + You've listened to %1 %n time(s). لقد استمعت إلى %1 %n مرة.لقد استمعت إلى %1 مرة %n.لقد استمعت إلى %1 مرتين %n.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات.لقد استمعت إلى %1 %n مرات. - + You've never listened to %1 before. لم تستمع إلى %1 من قبل. diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index ba813278f..654d3d5d0 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -175,32 +175,32 @@ connect and stream from you? Най-големи хитове - + Related Artists Свързани артисти - + Albums Албуми - + Cover - + Sorry, we could not find any albums for this artist! Съжалявам, но не откривам нито един албум за този артист! - + Sorry, we could not find any related artists! Съжалявам, но не откривам нито един подобен на този артист! - + Sorry, we could not find any top hits for this artist! Съжалявам, но не откривам нито една хитова песен на този артист! @@ -947,22 +947,17 @@ Tomahaw създаде доклад относно това и изпращай - + Open Queue Отвори опашката - - - The queue is currently empty. Drop something to enqueue it! - Тази опашка е празна в момента. Завлачи нещо за да създадеш нова. - - + Open Queue - %n item(s) - + Close Queue Затвори опашката @@ -1264,69 +1259,69 @@ Tomahaw създаде доклад относно това и изпращай SourceTreeView - + &Copy Link &Копирай адресът - + &Delete %1 &Изтрий %1 - + Add to my Playlists Добави към моите списъци - + Add to my Automatic Playlists Добави към моите автоматично-генерирани списъци - + Add to my Stations Добави към станциите ми - + &Export Playlist &Изнеси списък - + playlist списък - + automatic playlist автоматично-генериран списък - + station станция - + Delete %1? playlist/station/... Изтрий %1? - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? Наистина ли желаеш да изтриеш %1 <b>''%2" </b> - + Save XSPF Запази XSPF - + Playlists (*.xspf) Списъци (*.xspf) @@ -2635,7 +2630,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Албуми @@ -3325,32 +3320,32 @@ enter the displayed PIN number here: Подобни песни - + Sorry, but we could not find similar tracks for this song! Съжалявам, но не откривам нито една подобна на тази песен! - + You've listened to this track %n time(s). Ти си слушал тази песен %n път(и)Ти си слушал тази песен %n път(и) - + You've never listened to this track before. Никога не си слушал тази песен преди - + You first listened to it on %1. Първоначално си я слушал на %1 - + You've listened to %1 %n time(s). Слушал си %1 път(и)Слушал си %1 %n път(и) - + You've never listened to %1 before. Никога не си слушал %1 преди diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 418a138ff..2ac692eea 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -175,32 +175,32 @@ connect and stream from you? Grans Èxits - + Related Artists Artistes Relacionats - + Albums Àlbums - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -945,22 +945,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1261,69 +1256,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copia l'Enllaç - + &Delete %1 &Esborra %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist E&xporta la Llista de Reproducció - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Desa com XSPF - + Playlists (*.xspf) Llistes de reproducció (*.xspf) @@ -2627,7 +2622,7 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Àlbums @@ -3314,32 +3309,32 @@ introduïu el PIN aquí: Cançons Semblants - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Heu escoltat aquesta cançó %n cop.Heu escoltat aquesta cançó %n cops. - + You've never listened to this track before. No heu escoltat mai aquesta cançó abans. - + You first listened to it on %1. Vau escoltar aquesta cançó per primer cop el %1. - + You've listened to %1 %n time(s). Heu escoltat %1 %n cop.Heu escoltat %1 %n cops. - + You've never listened to %1 before. No heu escoltat mai %1 abans. diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index 47d331b6d..acdd07389 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -175,32 +175,32 @@ connect and stream from you? Top Hits - + Related Artists Ähnliche Künstler - + Albums Alben - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -945,22 +945,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1261,69 +1256,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiere Link - + &Delete %1 &Lösche %1 - + Add to my Playlists Zu meinen Playlisten hinzufügen - + Add to my Automatic Playlists Zu meinen Automatischen Playlisten hinzufügen - + Add to my Stations Zu meinen Stationen hinzufügen - + &Export Playlist Playliste &exportieren - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF XSPF speichern - + Playlists (*.xspf) Playlisten (*.xspf) @@ -2622,7 +2617,7 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Alben @@ -3309,32 +3304,32 @@ Tomahawk auf Twitter's Website authentifiziert hast: Ähnliche Lieder - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Du hast dieses Lied einmal gehört.Du hast dieses Lied %n mal gehört. - + You've never listened to this track before. Du hast dieses Lied noch nie angehört. - + You first listened to it on %1. Du hast dieses Lied zum ersten mal am %1 gehört. - + You've listened to %1 %n time(s). Du hast %1 einmal angehört.Du hast %1 %n mal angehört. - + You've never listened to %1 before. Du hast %1 vorher noch nie gehört. diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 3a8bd9116..931320c8e 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -176,32 +176,32 @@ connect and stream from you? Top Hits - + Related Artists Related Artists - + Albums Albums - + Cover Cover - + Sorry, we could not find any albums for this artist! Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! Sorry, we could not find any top hits for this artist! @@ -946,22 +946,17 @@ connect and stream from you? - + Open Queue Open Queue - - - The queue is currently empty. Drop something to enqueue it! - The queue is currently empty. Drop something to enqueue it! - - + Open Queue - %n item(s) Open Queue - %n item(s)Open Queue - %n item(s) - + Close Queue Close Queue @@ -1262,69 +1257,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copy Link - + &Delete %1 &Delete %1 - + Add to my Playlists Add to my Playlists - + Add to my Automatic Playlists Add to my Automatic Playlists - + Add to my Stations Add to my Stations - + &Export Playlist &Export Playlist - + playlist playlist - + automatic playlist automatic playlist - + station station - + Delete %1? playlist/station/... Delete %1? - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? Would you like to delete the %1 <b>"%2"</b>? - + Save XSPF Save XSPF - + Playlists (*.xspf) Playlists (*.xspf) @@ -2628,7 +2623,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -3315,32 +3310,32 @@ enter the displayed PIN number here: Similar Tracks - + Sorry, but we could not find similar tracks for this song! Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). You've listened to this track %n time(s).You've listened to this track %n time(s). - + You've never listened to this track before. You've never listened to this track before. - + You first listened to it on %1. You first listened to it on %1. - + You've listened to %1 %n time(s). You've listened to %1 %n time(s).You've listened to %1 %n time(s). - + You've never listened to %1 before. You've never listened to %1 before. diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 61fe02437..804bc8eb5 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -175,32 +175,32 @@ connect and stream from you? Grandes éxitos - + Related Artists Artistas relacionados - + Albums Álbumes - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -944,22 +944,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1260,69 +1255,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copiar enlace - + &Delete %1 &Eliminar %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist &Exportar lista de reproducción - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Guardar XSPF - + Playlists (*.xspf) Listas de reproducción (*.xspf) @@ -2626,7 +2621,7 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Álbumes @@ -3313,32 +3308,32 @@ introduzca su número PIN aquí: Temas Similares - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). Ha escuchado esta canción %n vez.Ha escuchado esta canción %n veces. - + You've never listened to this track before. Nunca ha escuchado este tema antes. - + You first listened to it on %1. Escuchó este tema pro primera vez en %1. - + You've listened to %1 %n time(s). Ha escuchado %1 %n vez.Ha escuchado %1 %n veces. - + You've never listened to %1 before. Nunca ha escuchado %1 antes. diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index ba5d41bd0..d7cddaf12 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -176,32 +176,32 @@ se connecter et streamer depuis chez vous ? Top Hits - + Related Artists Artistes similaires - + Albums Albums - + Cover - + Sorry, we could not find any albums for this artist! Désolé, on a pas pu trouver aucun album pour cet artiste! - + Sorry, we could not find any related artists! Désolé, on a rien trouvé par rapport a cet artite! - + Sorry, we could not find any top hits for this artist! Désolé, on a pas pu trouver aucun top hit pour cet artiste! @@ -946,22 +946,17 @@ se connecter et streamer depuis chez vous ? - + Open Queue Ouvrir la file d'attente - - - The queue is currently empty. Drop something to enqueue it! - Le queue est vide actuellement. Laisse tomber quelque chose pour l'ajouter! - - + Open Queue - %n item(s) Ouvrir la file d'attente - %n élémentOuvrir la file d'attente - %n éléments - + Close Queue Fermer la file d'attente @@ -1262,69 +1257,69 @@ se connecter et streamer depuis chez vous ? SourceTreeView - + &Copy Link &Copier le lien - + &Delete %1 &Supprimer %1 - + Add to my Playlists Ajoute a mes listes de lecture - + Add to my Automatic Playlists Ajoute a mes listes de lecture automatique - + Add to my Stations Ajouter à mes stations - + &Export Playlist &Exporter la liste de lecture - + playlist liste de lecture - + automatic playlist liste de lecture automatique - + station station - + Delete %1? playlist/station/... Supprimer %1? - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? Voulez-vous supprimer la %1 <b>"%2"</b>? - + Save XSPF Enregistrer XSPF - + Playlists (*.xspf) Listes de lecture (*.xspf) @@ -2628,7 +2623,7 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albums @@ -3315,32 +3310,32 @@ saisissez le numéro PIN ici : Piste similaire - + Sorry, but we could not find similar tracks for this song! Désolé, on a pas pu trouver aucune pistes pour cette chanson! - + You've listened to this track %n time(s). Vous avez écouté cette piste %n fois.Vous avez écouté cette piste %n fois. - + You've never listened to this track before. Vous n'avez encore jamais écouté cette piste. - + You first listened to it on %1. Vous l'avez écouté pour la première fois le %1. - + You've listened to %1 %n time(s). Vous avez écouté %1 %n fois.Vous avez écouté %1 %n fois. - + You've never listened to %1 before. Vous n'avez encore jamais écouté %1. diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 421954157..3251b8be7 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -175,32 +175,32 @@ connect and stream from you? 大ヒット曲 - + Related Artists 似たアーティスト - + Albums アルバム - + Cover - + Sorry, we could not find any albums for this artist! このアーティストのアルバムは見つかりませんでした。 - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -946,22 +946,17 @@ connect and stream from you? - + Open Queue キューを表示 - - - The queue is currently empty. Drop something to enqueue it! - キュの中には何も入っていません。何かキューにドロップしましょう! - - + Open Queue - %n item(s) キューを表示 - %n項目 - + Close Queue キューを隠す @@ -1262,69 +1257,69 @@ connect and stream from you? SourceTreeView - + &Copy Link リンクをコピー - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF XSPFを保存する - + Playlists (*.xspf) @@ -2618,7 +2613,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums アルバム @@ -3305,32 +3300,32 @@ Meta+Ctrl+Z 似ているトラック - + Sorry, but we could not find similar tracks for this song! この曲に似ているトラックが見つかりませんでした。 - + You've listened to this track %n time(s). このトラックは%n回聴いています。 - + You've never listened to this track before. このトラックを一度も聴いていません。 - + You first listened to it on %1. 初めてこの曲を聴いたのは、%1です。 - + You've listened to %1 %n time(s). %1を%n回聴いています。 - + You've never listened to %1 before. %1を一度も聴いていません。 diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 483f8596b..07723711e 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -175,32 +175,32 @@ connect and stream from you? Hity na Topie - + Related Artists Powiązani artyści - + Albums Albumy - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -944,22 +944,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1260,69 +1255,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiuj Link - + &Delete %1 &Usuń %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist &Eksportuj Listę - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Zapisz XSPF - + Playlists (*.xspf) Listy (*.xspf) @@ -2622,7 +2617,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Albumy @@ -3309,32 +3304,32 @@ wprowadź pokazany numer PIN tutaj: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 69c407f27..16bccd17e 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -175,32 +175,32 @@ connect and stream from you? Maiores sucessos - + Related Artists Artistas relacionados - + Albums Álbuns - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -944,22 +944,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1260,69 +1255,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Copiar link - + &Delete %1 &Eliminar %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist &Exportar lista de reprodução - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Salvar XSPF - + Playlists (*.xspf) Listas de reprodução (*.xspf) @@ -2621,7 +2616,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -3308,32 +3303,32 @@ colocar o número PIN mostrado aqui: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index e0f3592a8..cd6c2a1a8 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -176,32 +176,32 @@ connect and stream from you? Хиты - + Related Artists Похожие исполнители - + Albums Альбомы - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -946,22 +946,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1262,69 +1257,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Скопировать Cсылку - + &Delete %1 &Удалить %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist &Экспорт Плейлиста - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Сохранить XSPF - + Playlists (*.xspf) Плейлисты (*.xspf) @@ -2623,7 +2618,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums Альбом @@ -3309,32 +3304,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index c68912087..ee7e0cdf0 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -175,32 +175,32 @@ connect and stream from you? Största hits - + Related Artists Relaterade artister - + Albums Album - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -945,22 +945,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1261,69 +1256,69 @@ connect and stream from you? SourceTreeView - + &Copy Link &Kopiera länk - + &Delete %1 &Ta bort %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist &Exportera spellista - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF Spara XSPF - + Playlists (*.xspf) Spellistor (*.xspf) @@ -2617,7 +2612,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -3303,32 +3298,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 98e148293..fdd98d774 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -175,32 +175,32 @@ connect and stream from you? En Çok Dinlenenler - + Related Artists Benzer Sanatçılar - + Albums Albümler - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -944,22 +944,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1260,69 +1255,69 @@ connect and stream from you? SourceTreeView - + &Copy Link - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF - + Playlists (*.xspf) @@ -2616,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -3302,32 +3297,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index d8de2daf9..5063130e7 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -175,32 +175,32 @@ connect and stream from you? 最热曲目 - + Related Artists 相关艺人 - + Albums 专辑 - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -944,22 +944,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1260,69 +1255,69 @@ connect and stream from you? SourceTreeView - + &Copy Link - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF - + Playlists (*.xspf) @@ -2616,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums @@ -3302,32 +3297,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index d23368dc2..810820569 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -175,32 +175,32 @@ connect and stream from you? 流行精選 - + Related Artists 相關演出者 - + Albums 專輯 - + Cover - + Sorry, we could not find any albums for this artist! - + Sorry, we could not find any related artists! - + Sorry, we could not find any top hits for this artist! @@ -944,22 +944,17 @@ connect and stream from you? - + Open Queue - - - The queue is currently empty. Drop something to enqueue it! - - - + Open Queue - %n item(s) - + Close Queue @@ -1260,69 +1255,69 @@ connect and stream from you? SourceTreeView - + &Copy Link 複製鏈接 - + &Delete %1 - + Add to my Playlists - + Add to my Automatic Playlists - + Add to my Stations - + &Export Playlist 匯出播放清單 - + playlist - + automatic playlist - + station - + Delete %1? playlist/station/... - + Would you like to delete the %1 <b>"%2"</b>? e.g. Would you like to delete the playlist named Foobar? - + Save XSPF 儲存 XSPF - + Playlists (*.xspf) 播放清單(*.xspf) @@ -2616,7 +2611,7 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::NewReleasesPlugin - + Albums 專輯 @@ -3302,32 +3297,32 @@ enter the displayed PIN number here: - + Sorry, but we could not find similar tracks for this song! - + You've listened to this track %n time(s). - + You've never listened to this track before. - + You first listened to it on %1. - + You've listened to %1 %n time(s). - + You've never listened to %1 before. From b2becc6287a8edb1f61668b76c8d30151df640b0 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 15 Jun 2012 08:56:30 +0200 Subject: [PATCH 425/433] TWK-934: Don't crash when checking TreeView for jump-to-track --- src/libtomahawk/playlist/TreeView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/TreeView.cpp b/src/libtomahawk/playlist/TreeView.cpp index ae6580f13..57269b238 100644 --- a/src/libtomahawk/playlist/TreeView.cpp +++ b/src/libtomahawk/playlist/TreeView.cpp @@ -419,7 +419,7 @@ TreeView::onMenuTriggered( int action ) bool TreeView::jumpToCurrentTrack() { - if ( !m_proxyModel ) + if ( !m_proxyModel || !m_proxyModel->sourceModel() ) return false; scrollTo( m_proxyModel->currentIndex(), QAbstractItemView::PositionAtCenter ); From 4189f370a6c8fe9afc82e7192554814cb2b52b71 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 15 Jun 2012 10:11:03 +0300 Subject: [PATCH 426/433] Updated README. --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 7b47a9de1..8d9ced91b 100644 --- a/README +++ b/README @@ -17,7 +17,7 @@ Detailed building instructions for Ubuntu Detailed building instructions for OS X --------------------------------------- - See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_OS_X_Application_Bundle_on_Snow_Leopard_(10.6) + See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_OS_X_Application_Bundle_on_Snow_Leopard_(10.6)_and_Lion_(10.7) Doxygen Documentation --------------------- @@ -42,10 +42,10 @@ Dependencies QuaZip 0.4.3 - http://quazip.sourceforge.net/ Jreen 1.0.5 - http://qutim.org/jreen / https://github.com/euroelessar/jreen QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib + liblastfm 1.0.0 - http://github.com/eartle/liblastfm/ Third party libraries that we ship with our source: MiniUPnP 1.6 - http://miniupnp.free.fr/ - liblastfm 0.4.0 - http://github.com/jonocole/liblastfm/ Enjoy! From f20b8db56a0f28601c105387fe31e78a7994507b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 15 Jun 2012 10:18:53 +0300 Subject: [PATCH 427/433] * Attica & QuaZip are hard deps by now. --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 8d9ced91b..724c42cbf 100644 --- a/README +++ b/README @@ -35,11 +35,11 @@ Dependencies Boost 1.3 - http://www.boost.org/ CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml libechonest 1.2.0 - http://projects.kde.org/projects/playground/libs/libechonest/ + Attica 0.3.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ + QuaZip 0.4.3 - http://quazip.sourceforge.net/ The following dependencies are optional, but recommended: - Attica 0.3.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ - QuaZip 0.4.3 - http://quazip.sourceforge.net/ Jreen 1.0.5 - http://qutim.org/jreen / https://github.com/euroelessar/jreen QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib liblastfm 1.0.0 - http://github.com/eartle/liblastfm/ From 181bff132fcd09bc732696c7113338bfcb15560f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 15 Jun 2012 09:22:53 +0200 Subject: [PATCH 428/433] Require libechonest 1.2 as it's been out for ages and has some important fixes --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cb29dfeb..e2dc6a42a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,8 +101,8 @@ if(PHONON_FOUND) message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4") endif() -macro_optional_find_package(LibEchonest 1.1.10) -macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.1.10 is needed for dynamic playlists and the infosystem") +macro_optional_find_package(LibEchonest 1.2.1) +macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.2.1 is needed for dynamic playlists and the infosystem") macro_optional_find_package(CLucene 0.9.23) macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" "http://clucene.sf.net" TRUE "" "CLucene is used for indexing the collection") From 514841cf1cf050965646c097631e680537e6d319 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 15 Jun 2012 10:28:16 +0300 Subject: [PATCH 429/433] * Updated README. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 724c42cbf..5558b875b 100644 --- a/README +++ b/README @@ -34,7 +34,7 @@ Dependencies TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html Boost 1.3 - http://www.boost.org/ CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml - libechonest 1.2.0 - http://projects.kde.org/projects/playground/libs/libechonest/ + libechonest 1.2.1 - http://projects.kde.org/projects/playground/libs/libechonest/ Attica 0.3.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ QuaZip 0.4.3 - http://quazip.sourceforge.net/ From e18594994ce46649bb0b67def02e30a71efb15ce Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 15 Jun 2012 10:22:27 +0200 Subject: [PATCH 430/433] Show delete playlist dialog as a sheet on OS X --- src/sourcetree/SourceTreeView.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sourcetree/SourceTreeView.cpp b/src/sourcetree/SourceTreeView.cpp index 3e961441b..23b1a0b81 100644 --- a/src/sourcetree/SourceTreeView.cpp +++ b/src/sourcetree/SourceTreeView.cpp @@ -367,6 +367,10 @@ SourceTreeView::deletePlaylist( const QModelIndex& idxIn ) .arg( typeDesc ).arg( idx.data().toString() ), QMessageBox::Yes | QMessageBox::No, this ); +#ifdef Q_OS_MAC + askDelete.setWindowModality( Qt::WindowModal ); +#endif + int r = askDelete.exec(); if ( r != QMessageBox::Yes ) return; From cf4ea429f648d555b4f60eaaa05b3223131a9e9e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 13 Jun 2012 16:28:20 +0200 Subject: [PATCH 431/433] Fix focus issue with native cocoa views by turning off alien widgets --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 870bded10..9b360299d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -125,6 +125,10 @@ main( int argc, char *argv[] ) // This must go before QApplication initialisation. Tomahawk::macMain(); + // Fixes focus issue with NSSearchField, see QTBUG-11401 + // code taken from clementine:main.cpp:336 + QCoreApplication::setAttribute( Qt::AA_NativeWindows, true ); + // used for url handler AEEventHandlerUPP h = AEEventHandlerUPP( appleEventHandler ); AEInstallEventHandler( 'GURL', 'GURL', h, 0, false ); From 9d5d6b736006cf45f80fd4d93d05291f0c7659e2 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 15 Jun 2012 16:19:42 +0200 Subject: [PATCH 432/433] Don't track shared pointers --- src/CMakeLists.txt | 5 ++- src/libtomahawk/CMakeLists.txt | 3 +- src/libtomahawk/database/IdThreadWorker.h | 39 +++++++++++++++++++++++ src/libtomahawk/utils/Closure.cpp | 2 +- src/libtomahawk/utils/Closure.h | 6 ++-- 5 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 src/libtomahawk/database/IdThreadWorker.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d014d65bd..548fb9294 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,8 +13,6 @@ SET( QT_USE_QTNETWORK TRUE ) SET( QT_USE_QTXML TRUE ) SET( QT_USE_QTWEBKIT TRUE ) -add_definitions( -DQT_SHAREDPOINTER_TRACK_POINTERS ) - INCLUDE( ${QT_USE_FILE} ) INCLUDE( AddAppIconMacro ) @@ -96,8 +94,9 @@ SET( tomahawkUI ${tomahawkUI} INCLUDE_DIRECTORIES( . ${CMAKE_CURRENT_BINARY_DIR} + /usr/include/c++/v1/ - audio +audio database playlist network diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 2c0e5433c..07072cd62 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -15,7 +15,6 @@ include( ${QT_USE_FILE} ) add_definitions( ${QT_DEFINITIONS} ) add_definitions( -DQT_SHARED ) add_definitions( -DDLLEXPORT_PRO ) -add_definitions( -DQT_SHAREDPOINTER_TRACK_POINTERS ) set( libGuiSources @@ -333,6 +332,8 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/. ${LIBLASTFM_INCLUDE_DIRS}/.. ${CLUCENE_INCLUDE_DIRS} ${PHONON_INCLUDES} + /usr/include/c++/v1/ + playlist diff --git a/src/libtomahawk/database/IdThreadWorker.h b/src/libtomahawk/database/IdThreadWorker.h new file mode 100644 index 000000000..57d15184d --- /dev/null +++ b/src/libtomahawk/database/IdThreadWorker.h @@ -0,0 +1,39 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ +#ifndef IDTHREADWORKER_H +#define IDTHREADWORKER_H + +#include + +//#include +//#include + +class IdThreadWorker : public QThread +{ + Q_OBJECT +public: + explicit IdThreadWorker( QObject *parent = 0 ); + + void run(); + +private: + + +}; + +#endif // IDTHREADWORKER_H diff --git a/src/libtomahawk/utils/Closure.cpp b/src/libtomahawk/utils/Closure.cpp index 2b2a608bb..89c1b5a63 100644 --- a/src/libtomahawk/utils/Closure.cpp +++ b/src/libtomahawk/utils/Closure.cpp @@ -46,7 +46,7 @@ Closure::Closure(QObject* sender, Closure::Closure(QObject* sender, const char* signal, - std::tr1::function callback) + std::function callback) : callback_(callback) { Connect(sender, signal); } diff --git a/src/libtomahawk/utils/Closure.h b/src/libtomahawk/utils/Closure.h index 591712358..5ee2ef246 100644 --- a/src/libtomahawk/utils/Closure.h +++ b/src/libtomahawk/utils/Closure.h @@ -21,7 +21,7 @@ #include "DllMacro.h" -#include +#include #include #include @@ -64,7 +64,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable { const ClosureArgumentWrapper* val3 = 0); Closure(QObject* sender, const char* signal, - std::tr1::function callback); + std::function callback); void setAutoDelete( bool autoDelete ) { autoDelete_ = autoDelete; } @@ -87,7 +87,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable { void Connect(QObject* sender, const char* signal); QMetaMethod slot_; - std::tr1::function callback_; + std::function callback_; bool autoDelete_; boost::scoped_ptr val0_; From 6870cc6f88bc817482f33533b5616f53701642d8 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 15 Jun 2012 18:46:41 +0200 Subject: [PATCH 433/433] Revert previously mostly-bad commit, oops. --- src/CMakeLists.txt | 3 +- src/libtomahawk/CMakeLists.txt | 3 +- src/libtomahawk/database/IdThreadWorker.h | 39 ----------------------- src/libtomahawk/utils/Closure.cpp | 2 +- src/libtomahawk/utils/Closure.h | 6 ++-- 5 files changed, 6 insertions(+), 47 deletions(-) delete mode 100644 src/libtomahawk/database/IdThreadWorker.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 548fb9294..dd7e8dff5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,9 +94,8 @@ SET( tomahawkUI ${tomahawkUI} INCLUDE_DIRECTORIES( . ${CMAKE_CURRENT_BINARY_DIR} - /usr/include/c++/v1/ -audio + audio database playlist network diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 07072cd62..2c0e5433c 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -15,6 +15,7 @@ include( ${QT_USE_FILE} ) add_definitions( ${QT_DEFINITIONS} ) add_definitions( -DQT_SHARED ) add_definitions( -DDLLEXPORT_PRO ) +add_definitions( -DQT_SHAREDPOINTER_TRACK_POINTERS ) set( libGuiSources @@ -332,8 +333,6 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/. ${LIBLASTFM_INCLUDE_DIRS}/.. ${CLUCENE_INCLUDE_DIRS} ${PHONON_INCLUDES} - /usr/include/c++/v1/ - playlist diff --git a/src/libtomahawk/database/IdThreadWorker.h b/src/libtomahawk/database/IdThreadWorker.h deleted file mode 100644 index 57d15184d..000000000 --- a/src/libtomahawk/database/IdThreadWorker.h +++ /dev/null @@ -1,39 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2012 Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ -#ifndef IDTHREADWORKER_H -#define IDTHREADWORKER_H - -#include - -//#include -//#include - -class IdThreadWorker : public QThread -{ - Q_OBJECT -public: - explicit IdThreadWorker( QObject *parent = 0 ); - - void run(); - -private: - - -}; - -#endif // IDTHREADWORKER_H diff --git a/src/libtomahawk/utils/Closure.cpp b/src/libtomahawk/utils/Closure.cpp index 89c1b5a63..2b2a608bb 100644 --- a/src/libtomahawk/utils/Closure.cpp +++ b/src/libtomahawk/utils/Closure.cpp @@ -46,7 +46,7 @@ Closure::Closure(QObject* sender, Closure::Closure(QObject* sender, const char* signal, - std::function callback) + std::tr1::function callback) : callback_(callback) { Connect(sender, signal); } diff --git a/src/libtomahawk/utils/Closure.h b/src/libtomahawk/utils/Closure.h index 5ee2ef246..591712358 100644 --- a/src/libtomahawk/utils/Closure.h +++ b/src/libtomahawk/utils/Closure.h @@ -21,7 +21,7 @@ #include "DllMacro.h" -#include +#include #include #include @@ -64,7 +64,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable { const ClosureArgumentWrapper* val3 = 0); Closure(QObject* sender, const char* signal, - std::function callback); + std::tr1::function callback); void setAutoDelete( bool autoDelete ) { autoDelete_ = autoDelete; } @@ -87,7 +87,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable { void Connect(QObject* sender, const char* signal); QMetaMethod slot_; - std::function callback_; + std::tr1::function callback_; bool autoDelete_; boost::scoped_ptr val0_;

    PwJv1JGt#_u4<^2&e#(CueMG1S_YMj^T4oTti## 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 Dz>kdg literal 112854 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%0DCxc5pZqEAKfUMb#mx7 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 Q2QPrADr&+?<;~yyAFXBGNB{r; diff --git a/data/icons/tomahawk-icon-64x64.png b/data/icons/tomahawk-icon-64x64.png index d8b278ce58c87586997d53985a00725ca3a7ce75..e27712df7bc006ba87723329650c99d875290c74 100644 GIT binary patch literal 19778 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 literal 7051 zcmZ{JXHXN&_jPCznuO35Ap}B4n$nDvNTgQ@MWpv$1S!%*q$8Mz5)cHb0fY1^gf6{_ z^bXPl0!VLvejnct@9f?^bMKwAJ9GE!?96Voj+QbFM&Hvh$ABCT8BNQGg#;pJ` z(aR_*d26D+&^7ua9(}tnmHr2=&e!{O4SZuHG`#1phgV#Dfwz9e zJDR`iC=NQs32`IjsWVnirKfIK5a zBd~gJ?XIob>u%m{{tHuHukzO(bWJ_!q94^^hz5N{L|wcGb)nZJ1?%nDMUi1gV0I0G z-h#w}(I(-n#eFsZe>s8I86S4Gq(Tqz;dS}*DbdDK9bD%K(--tp$)-E^g*n?5(#f?* z8pC+=(LWRp)y4w%IAF;k4P5t}&-{x!m@8H^NEMCo_F*D`L6@gXFX_Llv_12Q@oKl< zx?gu&;`mp`KWSs$C$0yE@P03a(Fffm%N)5I{}QVW+MShz%?%?SC0VV%9y%m^)%J*n z1uY5@67lc!dS8nn>(9RJcPs>R|2OaTv;1szl8>v|oQXiOxZUrSTE|2B3$3McdXWa& zJ9P;nDT`M+yX-i9Ezh?q56IL+#)s6tvE0r!Z}Hp-w{@0EO0NWPr65MU^U#6&>gLPE zyxFUiIH53l{DR7A;z#c$Sk~#Zx&78I++ij#&?O=eL`~(#`<>p7on_palznl5>Xep4 zBY)hNJ2_D7$$rKj)4?85#RJV^kssFunj9fxCcDl?p6%Nz)&0tqxsbNBqyf9LmYaXt zt6uejbdb>J7L5vdbj#(R5`I)d)*^j*z=vEhZSzhr9!nwuPzO_dJrNU125znxuX-tG zYCe=0(>d?HTCsP;S&RL;X>!uMpHMp=a5D2tW5z0?fXiv&lQ@L%R4WVK`Ze)sMe?i$!dh0us$C=(Rui1bN4=kalF-+B9Hsy zBDtZrC7Is`fMy$ch>=jBTcvH#ReNz&ealOfn%;Fe@KgR_i!W^voz4ez_M8*)PqX}g z%dLUI6ED^dm<@Ts$$Q8x9sL2lcZ7bKv