Tutorial AppleScript Studio #2

chebfarid

Un playlist manager per il QuickTime Player – Seconda puntata

Abbiamo finito la prima puntata della realizzazone di un playlist manager per il QuickTime Player con AppleScript Studio, creando una interfaccia per il nostro programma che dovrebbe dovrebbe avere più o meno questo aspetto e i cui vari elementi avevamo anche collegato allo script principale dell’applicazione, QTPL.applescript

07collegamenti

In questa puntata scriveremo il codice che servirà per aprire i filmati di cui si occuperà il programma, aggiungerli alla playlist e riprodurli.

1. Tipologie di file supportati – Uniform Type Identifiers

Prima di farlo bisogna aprire una finestra teorica: La nostra applicazione per definizione collaborerà con il QuickTime Player, i file che elaborerà sono per definizione filmati compatibili con QuickTime.

Non ci interessano documenti html oppure foglio di calcolo Excel. Il modo più semplice per far sì che a priori vengano esclusi tutti i file che non hanno a che vedere con QuickTime e che quelli giusti siano selezionabili per le operazioni che svilupperemo fra poco, oppure anche aggiungibili alla playlist via “drag and drop”, è definire al lancio del programma che tipi di documenti siano compatibili con l’applicazione.

Per rendere questa informazione accessibile globalmente per tutto lo script e i suoi handler definiamo gli Uniform Type Identifiers (UTI) come property in cima allo script:

property supportedFiles : {“com.apple.quicktime-movie”, “public.avi”, “public.mpeg”, “public.mpeg-4″, “com.microsoft.windows-media-wmv”}

I formati supportati saranno quindi

  • - filmati QuickTime (mov)
  • - filmati AVI
  • - filmati MP4
  • - filmati MPEG
  • - filmati di Windows Media Player (wmv)

Nota: se tutti questi formati sono compatibili con la vostra versione del QuickTime Player dipende dalla vostra configurazione e dei plugin che avete installato.

Chi vuole approfondire l’argomento degli UTI troverà su questa pagina una lista di tutti gli identificatori definiti per Mac OS X Tiger: http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/utilist/chapter_4_section_1.html

 

2. Aprire file e aggiungerli alla playlist

Ci saranno tre modi per aggiungere dei filmati alla playlist:

  1. - tramite il pulsante [ + ]
  2. - tramite la voce “Aggiungi alla playlist…” del menu (che non abbiamo ancora creato)
  3. - tramite il drag and drop

Le prime due tecniche sono identiche e quindi per non dover scrivere due volte lo stesso codice creiamo un handler (una funzione, come si chiamerebbe in altri linguaggi di programmazione) che gestisce questa operazione.

Prima però c’è da spiegare un altro meccanismo. Vogliamo che i file scelti poi vengano visualizzati nella nostra playlist che tecnicamente è un NSTableView. Questa tabella deve rispecchiare tutte le modifiche (aggiunte oppure rimozioni) della struttura dati della cui visualizzazione è responsabile. La struttura dati a cui fa riferimento un table view si chiama data source. Il nostro codice deve raccogliere, fornire ed aggiornare le informazioni per questa data source e dopo ogni modifica verrà invocato un refresh della tabella per aggiornare la visualizzazione.

Abbiamo quindi bisogno di un contenitore dove raccogliere i file/filmati che ci interessano. Il contenitore standard di AppleScript è di tipo list (lista). E perchè questa lista è di importanza globale per l’intera applicazione definiamo anch’essa come property dello script, subito sotto la property dei formati supportati:

property movieFiles : {}

Come vedete, al lancio dello script, movieFiles è niente di più di una lista vuota {} che poi però verrà manipulata parecchie volte durante l’esecuzione del programma.

La data source invece è un’affare che riguarda la tabella stessa (da questo aspetto AppleScript Studio è molto object orientated: se non è strettamente necessario un approccio globale ogni oggetto si occupa degli affari suoi e comunica i risultati all’applicazione) e della sua definizione se ne occuperà un handler dedicato all’aggiornamento della tabella. Anticipo che si chiamerà updatePlaylist() e lo scriveremo fra poco.

Torniamo quindi al punto di partenza e creiamo il handler che si occupa dell’apertura di file/filmati da aggiungere.
Creare un handler è semplice, la sua struttura è:

on [nomeHandler]()
– codice da eseguire
end [nomeHandler]

Chiamiamo il handler, dato che si occupa dell’aggiunta di filmati/movies, addMovies() Notate le due parentesi: tra queste parentesi si possono inserire dei parametri (ad esempio i documenti da elaborare) da passare al handler. Anche se, come nel nostro caso, il handler non ha parametri, sono comunque da aggiungere le parentesi vuote.
Il codice di addMovies() è il seguente:

on addMovies()
set newMovie to choose file of type supportedFiles with prompt “Scegli dei filmati da aggiungere alla playlist:” without invisibles
set end of movieFiles to newMovie
my updatePlaylist()
end addMovies

Cosa succede qua?
La prima riga dice di scegliere un file nel formato definito nella lista supportedFiles, ignorando file invisibili.
La seconda riga aggiunge questo file alla lista movieFiles, il nostro contenitore globale dei filmati scelti
La terza riga chiama un altro handler, updatePlaylist() (non dimenticate la parola chiave my quando chiamate un handler definito da voi), e questo updatePlaylist() poi tradurrà il contenuto di movieFiles in una data source che userà per la visualizzazione nella tabella.

Prima che completiamo il codice con l’implementazione dell’handler updatePlaylist() – che non esiste ancora – fermiamoci un attimo per vedere come far eseguire questa routine della nostra applicazione: abbiamo detto che va legata (fra altro) al pulsante [+] per il quale, se vi ricordate, nella prima puntata avevamo già definita l’azione “clicked” nell’AppleScript dell’applicazione, oltre a dargli il nome “aggiungi” con il quale verrà identificato all’interno dello script.

Per eseguire le poche righe scritte sopra basta quindi aggiungere al già esistente handler on clicked theObject questa istruzione:

on clicked theObject
if name of theObject = “aggiungi” then
my addMovies()
end if
end clicked

E ora finiamo il handler con la definizione di updatePlaylist():
Abbiamo riempito la lista movieFiles con i file/filmati scelti con addMovies().

Adesso dobbiamo 

  • estrapolare da questi file il titolo e il tipo, perchè sono queste due le informazioni che vengono visualizzate nella tabella “elencoFilmati”
  • raccogliere queste informazioni in un’altra lista
  • creare la data source responsabile per le visualizzazioni della tabella e riempirla con le informazioni raccolte sopra
  • forzare la tabella ad aggiornarsi per visualizzare i risultati

Ecco il handler completo; in corsivo commenti e spiegazioni:

on updatePlaylist()
creazione di movieRecords come lista vuota
set movieRecords to {}
(* la lista movieFiles va esimanata file per file e i valori per “name” e “kind”
vengono salvati in una “mini-lista” {n, k} 

per prevedere a eventuali errori di esecuzione tutto viene inserito in un bloco “try – end try” *)
try
repeat with aMovie in movieFiles
set n to name of (get info for aMovie)
set k to kind of (get info for aMovie)
set end of movieRecords to {n, k}
end repeat
on error e number n
display dialog e buttons {“OK”}
end try

creazione della data source:
set theDataSource to make new data source at end of data sources with properties {name:”movies”}
(* la data source è strutturata in colonne (columns), pratico, visto che ci serve per riempire una tabella…
Creiamo quindi una colonna “Title” e una “Kind” che corrispondono alle colonne della nostra tabella *)
make new data column at end of data columns of theDataSource with properties {name:”Title”, sort order:ascending, sort type:alphabetical, sort case sensitivity:case sensitive}
make new data column at end of data columns of theDataSource with properties {name:”Kind”, sort order:ascending, sort type:alphabetical, sort case sensitivity:case sensitive}
Definiamo esplicitamente che il nostro table view va gestito da “theDataSource” 
set data source of table view 1 of scroll view 1 of window 1 to theDataSource
aggiungiamo le informazioni raccolte in “movieRecords” a “theDataSource”
append theDataSource with movieRecords
infine, ordiniamo alla tabella di aggiornarsi per visualizzare i nuovi risultati:
tell table view 1 of scroll view 1 of window 1 to update
end updatePlaylist

Complicato? Sicuramente un po’ complesso, ma una volta capito il concetto che il contenuta di una tabella (table view) è gestito da un contenitore di tipo data source, il quale a sua volta necessità di informazioni raccolte nelle varie fasi dell’esecuzione di un programma, le cose diventano più chiare. (Per il resto, concetti simili a questo vengono impiegati anche in linguaggi di programmazione veri come Objective-C e Java).

E’ giunto il momento per salvare il lavoro e testarlo: in Xcode scegliete dal Menu “Build” il comando “Build and Run” [Cmd+R].
Cliccate il pulsante [+] (se vi ricordate avevamo anche impostato una scorciatoia da tastiera: [Cmd +] e si apre un file chooser come lo conosciamo da tanti programmi per OS X:

Notate che, come previsto, possiamo solamente scegliere dei file compatibili con QuickTime, tutti gli altri appaiono grigi (dimmed out). Scegliete un file/filmato dal vostro hard disk (potete farlo quante volte vi piace) e voilà, ecco come si presenta la tabella del nostro programma dopo “tre giri”:

3. Quando un programma si sveglia: awake from nib

Nell’immagine sopra noterete inoltre che la mia playlist ha un titolo: “Playlist senza titolo“, da dove l’ha preso?

Mi sono dimenticato di spiegare un handler semplice ma importante che si chiama awake from nib: si tratta di una istruzione che fa parte del repertorio di default di Xcode e Interface Builder. In awake from nib (in italiano qualcosa come “risveglio dell’interfaccia”) si possono definire dei comportamenti e delle azioni che il programma esegue ogni volta che viene lanciato. Di seguito questa funzione ci sarà utile per parecchie operazioni, al momento ci definiamo solo che ogni volta che il programma si apre il titolo della nuova finestra sarà appunto “Playlist senza titolo” (presto imparemo anche come questo titolo cambierà quando abbiamo scritto il codice per salvare una playlist o aprire una vecchia playlist precedentemente salvata).

Come va implementato awake from nib ?

In Interface Builder selezionate la finestra della nostra applicazione, basta un click sulla barra del titolo. Nell’Inspector AppleScript vedrete una voce “Nib” con l’azione “awake from nib”. Selezionatela, salvate e aprite il nostro script QTPL.applescript.

Come nel caso delle azioni “clicked” vedrete ora un nuovo handler vuoto:

on awake from nib theObject

end awake from nib

Modificatelo in questo modo:

on awake from nib theObject
set title of window 1 to “Playlist senza titolo”
end awake from nib

 

4. Rimuovere dei brani dalla playlist

Ora sappiamo come aprire file e aggiungerli alla playlist. E se vogliamo togliere un brano che non ci piace più?

Avrete già capito che il pulsante che si occuperà di questa operazione sarà il nostro [ - ] , ma gli dobbiamo ancora scrivere la sua parte nello spettacolo. Riempendo la playlist e cliccando sulle righe avrete già notato che si possono fare delle selezioni nella tabella, e questo senza che noi avessimo scritto una riga di codice! Infatti, la possibilità di selezionare ed evidenziare delle righe è un comportamente standard degli oggetti NSTableView, tutto il necessario per queste operazioni è già inserito di default in un oggetto di questo tipo quando viene creato in Xcode. Tocca a noi però definire che cosa fare con una o più righe selezionate nella tabella.

Dobbiamo quindi comunicare ad un nuovo handler removeMovies() quali sono i filmati selezionati per la rimozione.
Il handler farà una raccolta dei filmati che rimangono attivi per creare una nuova data source con questi filmati non remossi e la tabella si aggiorna per visualizzare i risultati.
La classe NSTableView ci aiuta perchè il suo repertorio comprende una property selected rows ! Questa lista delle righe selezionate in realtà è una lista degli indici delle righe selezionate.

Ecco il codice di removeMovies():

on removeMovies()
una lista che raccoglie i filmati da cancellare
set moviesToRemove to {}
una seconda lista temporanea che raccoglie i filmati “sopravissuti”
set tempMovieFiles to {}
la lista delle righe selezionote, o meglio dei loro indici:
set rowIndex to selected rows of table view “elencoFilmati” of scroll view 1 of window 1

un loop attraverso la lista delle righe selezionate
repeat with r in rowIndex
(* l’elemento della lista “movieFile” con l’indice “r” viene aggiunto 
alla lista dei cancellabili “moviesToRemove” *)
set end of moviesToRemove to (item r of movieFiles as alias)
end repeat

un loop, filmato per filmato (oneMovie) attraverso la “lista madre”, “movieFiles”:
repeat with oneMovie in movieFiles
se il filmato “aMovie” non fa parte delle lista dei cancellabili, allora
if oneMovie is not in moviesToRemove then
va aggiunto alla lista dei “sopravissuti”
set end of tempMovieFiles to oneMovie
end if
end repeat

la vecchia “lista madre” va sostituita con la lista dei sopravissuti
set movieFiles to tempMovieFiles
la lista dei filmati selezionati va svuotata per fare spazio a nuove selezioni
set rowIndex to {}
(* si invoca di nuovo upDatePlaylist che come nell’handler addMovies()
aggiornera’  la data source e la visualizzazione della tabella *)
my updatePlaylist()
end removeMovies

Avete visto che come nel handler per l’aggiunta dei filmati va chiamato alla fine lo stesso identico handler updatePlaylist(), perchè, qualsiasi cosa noi facciamo con i nostri dati, i risultati di queste operazioni devono corrispondere alla struttura dei dati visualizzati nella nostra tabella.

Last not least, dobbiamo collegare questo handler al pulsante [ - ] , modificando il handler on clicked theObject nel modo seguente:

on clicked theObject
if name of theObject = “aggiungi” then
my addMovies()
else if name of theObject = “elimina” then
my removeMovies()
end if
end clicked

Salvate ed eseguite l’applicazione e controllate il corretto funzionamente dei due pulsanti (“Build and Run” [Cmd+R] ).

Il tempo vola e comunque di novità ce n’erano tante in questa seconda puntata. Nella prossima ci occuperemo di cose elementari come la riproduzione dei brani delle nostre playlist e del salvataggio delle playlist create con QTPL. 

Come per la precedente, potete scaricare il source code di questa puntata qui . Se avete dubbi, domande, suggerimenti, parliamone su Tevac!

Tags: , ,

4 Commenti a “Tutorial AppleScript Studio #2”

  1. jacoping 10 novembre 2009 at 22:48 #

    ciao!
    ho seguito i primi due tutorial su applescript studio e li ho trovati utilissimi, ma quale delusione scoprendo che non ce n’è più!!!
    sono per caso pubblicati da qualche altra parte?
    altrimenti mi forniresti il suorce code dell’applicazione finita così in qualche modo posso andare avanti da solo?
    la mia mail è jacopo punto ammendola chiocciola gmail punto com
    grazie!!
    J

  2. robrota 10 novembre 2009 at 22:52 #

    speriamo che l’autore del tutorial, leggendo il tuo commento, sia “stimolato” a completare l’opera… :-)

  3. chebfarid 18 novembre 2009 at 18:41 #

    @jacoping
    Ciao Jacopo,
    hai proprio ragione, mi dispiace di non trovare il tempo per dedicarmi alla prossima puntata. Spero proprio di farcela questo mese!

    Good scripting
    Farid

Trackbacks/Pingbacks

  1. Tutorial AppleScript Studio #2 - feedreader aggregatore di notizie web 2.0 and more … - 28 febbraio 2009

    [...] View post:  Tutorial AppleScript Studio #2 [...]

Lascia un Commento