Visualizzazione post con etichetta java. Mostra tutti i post
Visualizzazione post con etichetta java. Mostra tutti i post

domenica 8 gennaio 2017

Wastats, app Android per le statistiche whatsapp

Avete mai avuto la "curiosità" di fare le statistiche dei vostri messaggi whatsapp? Fare una ricerca per periodi, mittente, testo, argomento ecc.? Ebbene, io si. Dopo varie soluzioni avallate per creare una app del genere, sono arrivato a una soluzione concreta per farlo.

Si sa, il database whatsapp è criptato, prima aveva una chiave di cifratura che si era conosciuta, ma con i nuovi aggiornamenti whatsapp era diventata obsoleta. Ho cercato più volte di decriptare quel database, ma non ci sono mai riuscito con una soluzione duratura nel tempo. Oltretutto, ultimamente le conversazioni sono criptate end-to-end, quindi è ancora più difficile.

La soluzione che ho adottato è quella di esportare una singola conversazione, gruppo o broadcast tramite testo (è possibile inviarlo tramite e-mail in formato testo).
La piccola app che ho scritto non fa altro che leggere questo file di testo, fare il parsing e caricarlo tutto su un database interno della app, in modo da fare query. La versione attuale permette di interrogare il database manualmente con le query, ma sto già lavorando a un'interfaccia più user-friendly con i filtri. 

Per ora Wastats è fortemente in BETA, l'interfaccia è molto spartana, perché finora mi sono dedicato principalmente alla part funzionale.
Attualmente ci sono essenzialmente due funzioni: quella per caricare il database con nuovi dati di una nuova conversazioni e quella per interrogare il database. 

Aggiorna database

Questa è la funzione per caricare nuovi dati. "Seletta" è un tasto che non fa nulla, l'ho messo all'inizio pensando mi dovesse servire invece no, stessa cosa per "Crea database". Basta premere il tasto aggiorna e il programma cercherà nella memoria esterna (o nella cartella download, non ricordo) i file di tipo testo che iniziano con il filtro "Chat Whatsapp". Dopo che vengono elencati, basta premere il file che si vuole caricare, e vi verrà chiesto un "argomento", ovvero una stringa che identifica la conversazione esempio "famiglia", oppure "gruppo amici", per facilitare l'estrazione dei dati. Dopo di che premere OK e una progress bar ci mostrerà l'avanzamento del processo. 









Interroga database

Da qui invece si fanno le query sqlite vere e proprie sul database, come da screenshot:
 

Qui c'è il link con lo zip che contiene l'apk:
https://drive.google.com/file/d/0B2K4nLFPcS-obTZBTzdMNU5RYUE/view?usp=sharing



giovedì 9 giugno 2016

JMusicMan versione 5.0

Dopo il primo post su JMusicMan, adesso ho migliorato il programma sotto diversi aspetti. 

La funzione principale rimane invariata, ma adesso grazie al supporto di un'altra libreria, il programma gestisce diversi file audio.

Ecco le migliorie principali:

  • La lettura dei tag non presenta più bug; anzi è prevista la funzione "Reset tag" per creare un nuovo tag e non entrare in contrasto con tag creati precedentemente da programmi diversi (la cui compatibilità purtroppo, viene a cadere)
  • Eliminazione delle cartelle vuote e notifica nel caso ci siano cartelle contenenti esclusivamente materiale non-audio
  • Gestione delle ambiguità: se due o più file hanno lo stesso tag si presentano due casi:
    • I file hanno la stessa durata quindi probabilmente sono uguale; si chiede all'utente se eliminare i doppi o crearne una copia rinominata
    • I file hanno durata diversa: alla fine della procedura di aggiornamento viene chiesto di modificare i tag dei file audio, pena l'esclusione della libreria. Il messaggio si ripresenterà al successivo aggiornamento.
Tra le caratteristiche che tuttora sono in via di sviluppo (anzi sono già state implementate, ma la versione è beta) figurano:
  • Ricerca di canzoni nella libreria
  • Pannello laterale per visualizzare alcune informazioni
  • Vari automatismi fra cui numerazione automatica, riconoscimento traccia e riconoscimento tracce album tramite il servizio musicbrainz
  • Modifica titoli massivamente (in sviluppo)
Questo è uno screenshot della versione beta:

Panoramica

All'avvio il programma cercherà automaticamente file audio nella cartella "musica" del computer e comincia la catalogazione:

Se si sono verificati errori (ambiguità di tag o altro) allora una finestra di dialogo mostrerà le tracce "problematica" e chiederà all'utente la modifica dei tag:


L'utente può modificare le informazioni direttamente dentro il form. E' possibile selezionare anche più tracce. Titolo e numero traccia si memorizzano dinamicamente scrivendo nei relativi campi, Artista e Album invece si memorizzando premendo i tasti coi tre puntini sulla destra.

È anche possibile correggere le tracce anche quando sono taggate, sia singolarmente che massivamente (in quest'ultimo caso è possibile modificare solo Artista, Album e Immagine):

La sincronizzazione dei dispositivi

È una funzione che non ho curato molto ultimamente, ma comunque ricordo funzionava a dovere. Dopo aver impostato il dispositivo contenente il file .is_audio_player, il programma sincronizza la libreria del PC con quella del dispositivo trovando le tracce da copiare e quelle da eliminare semplicemente comparando due file XML che sono quelli che si trovano nella cartella Musica ("JMusicManLibrary.xml")

giovedì 25 febbraio 2016

L'applicativo scritto per la mia tesi di laurea

Per la mia tesi di laurea ho scritto un software in java per automatizzare un calcolo che, anche fatto con un foglio di calcolo, richiedeva della manualità e quindi più tempo. 
Il programma sviluppato non è certo chissà cosa di complicato, ma essendo un programmatore, ho voluto inserire qualcosa che riguardasse la programmazione nella mia tesi di laurea. 

Schermata del software
Piccolo incipit.
La mia tesi di laurea "Produzione, gestione e smaltimento dei rifiuti citotossici e citostatici
nell’AOUP “Paolo Giaccone” di Palermo", redatta con uno stage dove ho raccolto dati, riguarda lo smaltimento dei rifiuti citotossici e citostatici. I dati che avevo raccolto riguardavano le quantità di rifiuti relativi a certi farmaci prodotti ogni giorno, e ogni farmaco è caratteristico di un reparto. Il mio programma non fa altro che calcolare le percentuali del numero di farmaci effettivamente utilizzati per ogni reparto, su scala settimanale. Posso decidere se utilizzare i dati di 1, 2 o 3 settimane, come si nota sullo screenshot. Inseriti i file .csv, formati in questo modo:


poi basta premere sul tasto Elabora, che nel log del programma vengono mostrati i dati in output, che verranno comunque esportati in altrettanti file .csv. 

Dando un'occhiata al codice, ho utilizzato la libreria esterna opencsv versione 3.4 per gestire i file csv in maniera veloce. 

public class Farmaci {

    public static double oncologia=0;
    public static double ematologia=0;
    public static double neurologia=0;
    public static double urologia=0;
    public static double reumatologia=0;
    public static double onco=0;
    public static double ema=0;
    public static double neuro=0;
    public static double uro=0;
    public static double reuma=0;
    public static Integer[] ID;
    public static int primo=0, secondo=0, terzo=0;
    /*numero di farmaci*/
    public static int count;
    public static Frame frame = new Frame();
    
    
    public static void main(String[] args) {
        ID = new Integer[67];
        for (int i=0;i<67;i++)
            ID[i] = new Integer(0);
        frame.setVisible(true);
    }
}

Questa è la classe principale dove dichiaro le variabili principali. Nel metodo main inizializzo l'array di Integer di 67 elementi, tanti quanto il numero di farmaci. 
Riporto dalla mia tesi:

Il seguente codice scritto in linguaggio Java è la funzione principale del software che ho scritto. Essa riceve in input un intero da 1 a 3 che denota la casella contenente il percorso del file .csv da elaborare, quindi apre il file, legge iteratamente ogni record ed effettua le opportune operazioni, per poi infine scrivere le percentuali nelle 5 label relative a ogni reparto, e riportare altre informazioni nella casella di testo “sum”.
private voidelaboraFile(intindiceCasellaDiTesto){
try{
CSVReadercsvReader;
/*  Controllo quale casella del file esaminare */
if (indiceCasellaDiTesto==1)
csvReader = new CSVReader(new java.io.FileReader(new File(this.file1textfield.getText())),';');
else if (indiceCasellaDiTesto==2)
csvReader = new CSVReader(new java.io.FileReader(new File(this.file2textfield.getText())),';');
else if (indiceCasellaDiTesto==3)
csvReader = new CSVReader(new java.io.FileReader(new File(this.file3textfield.getText())),';');
else //DevoinizializzareobbligatoriamentecsvReader
csvReader = new CSVReader(new java.io.FileReader(new File(this.file1textfield.getText())),';');
String[] row=null;
/* Leggo dal file .csv */
while ((row = csvReader.readNext())!=null){
if (!row[0].equals("0")){ //controllo se è la riga terminale
Farmaci.ID[Integer.parseInt(row[0])-1]=Farmaci.ID[Integer.parseInt(row[0])-1]+Integer.parseInt(row[2]);      //memorizzo il farmaco con il numero delle volte che è stato utilizzato
/* Da qui in poi verifico a quale reparto “appartiene” ed eseguo le dovute operazioni
if (row[1].equals("oncologia"))
Farmaci.onco=Farmaci.onco+Integer.parseInt(row[2]);
else if (row[1].equals("oncoema")){
Farmaci.onco=Farmaci.onco+0.5*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.5*Integer.parseInt(row[2]);
}
else if (row[1].equals("oncoemaneuo")){
Farmaci.onco=Farmaci.onco+0.3333*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.3333*Integer.parseInt(row[2]);
Farmaci.neuro=Farmaci.neuro+0.3333*Integer.parseInt(row[2]);
}
else if (row[1].equals("ema")){
Farmaci.ema = Farmaci.ema+Integer.parseInt(row[2]);
}
else if (row[1].equals("oncoemaurol ")){
Farmaci.onco=Farmaci.onco+0.3333*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.3333*Integer.parseInt(row[2]);
Farmaci.uro=Farmaci.uro+0.3333*Integer.parseInt(row[2]);
}
else if (row[1].equals("oncoemaurol")){
Farmaci.onco=Farmaci.onco+0.3333*Integer.parseInt(row[2]);
Farmaci.ema=Farmaci.ema+0.3333*Integer.parseInt(row[2]);
Farmaci.uro=Farmaci.uro+0.3333*Integer.parseInt(row[2]);
}
else if (row[1].equals("reumatologia")){
Farmaci.reuma=Farmaci.reuma+Integer.parseInt(row[2]);
}
/* Aumento il contatore del numero di flaconi utilizzati */
Farmaci.count = Farmaci.count+Integer.parseInt(row[2]);
}
else{
/* Operazioni da effettuare quando si arriva a fine giornata.
   ovvero il calcolo delle percentuali */
Farmaci.oncologia = (Farmaci.onco/Farmaci.count)*100;
Farmaci.ematologia = (Farmaci.ema/Farmaci.count)*100;
Farmaci.urologia = (Farmaci.uro/Farmaci.count)*100;
Farmaci.neurologia = (Farmaci.neuro/Farmaci.count)*100;
Farmaci.reumatologia = (Farmaci.reuma/Farmaci.count)*100;
oncologia.setText(String.format("%.2f",Farmaci.oncologia)+"%");
ematologia.setText(String.format("%.2f",Farmaci.ematologia)+"%");
urologia.setText(String.format("%.2f",Farmaci.urologia)+"%");
neurologia.setText(String.format("%.2f",Farmaci.neurologia)+"%");
reumatologia.setText(String.format("%.2f",Farmaci.reumatologia)+"%");
}
}
/* Trovo i tre farmaci più utilizzati */
int primo=0, secondo=0, terzo=0;
for (int i=0;i<67;i++){
if (Farmaci.ID[i]>Farmaci.ID[primo])
primo = i;
}
for (inti=0;i<67;i++){
if ((Farmaci.ID[i]>Farmaci.ID[secondo])&&(Farmaci.ID[i]<Farmaci.ID[primo]))
secondo = i;
}
for (inti=0;i<67;i++){
if ((Farmaci.ID[i]>Farmaci.ID[terzo])&&(Farmaci.ID[i]<Farmaci.ID[secondo]))
terzo = i;
}
/* Scrivo il tutto nella casella di testo per mostrare i dati. */
sum.append("Numero di farmaci utilizzati: "+Farmaci.count+"\n");
sum.append("I tre farmaci più utilizzati (per ID): \n");
sum.append("#"+Integer.toString(primo)+": "+Integer.toString(Farmaci.ID[primo])+" usi\n");
sum.append("#"+Integer.toString(secondo)+": "+Integer.toString(Farmaci.ID[secondo])+" usi\n");
sum.append("#"+Integer.toString(terzo)+": "+Integer.toString(Farmaci.ID[terzo])+" usi\n");
}
/* Controllo degli errori */
catch(java.io.IOException e){
sum.append("File non trovato\n");
}
catch(Exception e){
sum.append("Si è verificato un errore: "+e.getMessage()+”\n”);
}
}

lunedì 31 agosto 2015

Un programma per aggiungere lo "staccato" agli spartiti in MusicXML

Prima
Dopo
Ne approfitto per rispolverare questo blog su cui non scrivo da molto.

Ho sviluppato un programma in java che in principio doveva essere un plugin interno a MuseScore (un software libero di notazione musicale), ma viste alcune complicazioni, ho deciso di creare un programma in java con cui si può fare tutto.

In pratica esso agisce su un file MusicXML (file standard per la notazione musicale che MuseScore può esportare facilmente), e aggiunge lo "staccato" alle note seguite da una pausa avente lo stesso valore. Rende lo spartito più leggibile.

L'ho sviluppato per mettere fine una volta per tutte alla modifica manuale degli spartiti. 

Il prossimo passo sarà quello di aggiungere il punto a quelle note legate a una stessa nota ma con la metà del loro valore.

Per sviluppare il programma (sviluppato e lasciato in linea di comando) mi sono servito della libreria JDOM per manipolare i file XML.

Da qui potete scaricare sorgenti e compilati del programma. 

Per il funzionamento è necessario estrarre in una cartella AddStaccato.jar e le directory DTD e lib.
Per lanciare il programma devi avere java sul tuo pc e le variabili d'ambiente impostate.
Quindi lanci il comando:

java -jar <percorso_del_programma_addstaccato> <opzioni> <valori> nomefile.xml

le opzioni sono:

-r seguito da un numero, specifica il numero della parte (=rigo musicale) da modificare
-i seguito da due numeri che rappresentato la prima e l'ultima battuta (incluse) da modificare

Esempio:


java -jar <percorso_del_programma_addstaccato> -r 4 -i 15 74 nomefile.xml

modifica le battute comprese tra 15 e 74 (inclusi) del rigo numero 4 di nomefile.xml

bye


martedì 8 ottobre 2013

Come leggere un file XML in Java

Molto spesso capita di interfacciarsi con applicazioni tramite XML, oppure usufruire delle API di un servizio web che esportano i propri dati su dei file XML. Ebbene, in questo post spiegherò come leggere un file XML da Java, supponendo che il file XML sia una risorsa web, in particolare questa: 


che è un file che ci dà informazioni su una traccia musicale (Believe di Cher). Per semplicità, supponiamo che a noi interessa sapere la durata di questo brano e la risorsa immagine che è la cover dell'album a cui appartiene. Innanzitutto, per leggere un file XML l'applicazione che si propone di farlo deve conoscere come è strutturato questo file, specifico per ogni servizio. Per esempio, questo file di last.fm ha come root element il tag <lfm status="ok"> che ci dice che il servizio di last.fm attualmente funziona. Tralasciando altre descrizioni del file XML, arriviamo a quello che ci interessa: la durata del brano si trova in <track>--><duration>, mentre l'immagine dell'album si trova in <album>--><image>. Nota che ci sono quattro varianti del tag <image> che si differenziano per il valore del parametro "size". Supponiamo a noi interessa una dimensione media quindi scegliamo il valore "medium" del suddetto parametro. Passiamo allora al codice. 

Innanzitutto ci serve una libreria; io uso e mi trovo bene con jdom (www.jdom.org). 
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

public class prova {
    public static void main(String[] args) {
        try {
            SAXBuilder builder = new SAXBuilder();
            Document document= builder.build("http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=91de4539bbb0d5b2bdc36d23d3906246&artist=cher&track=believe");
            Element duration = document.getRootElement().getChild("track").getChild("duration");
            System.out.printf("La durata è: "+duration.getValue());
            java.util.List albumImage = document.getRootElement().getChild("track").getChild("album").getChildren("image");
            String albumImageResource = "";
            java.util.Iterator iteratore = albumImage.iterator();
            while (iteratore.hasNext()){
                Element elemento = (Element)iteratore.next();
                if (elemento.getAttributeValue("size").equals("medium")) {
                    albumImageResource = elemento.getValue();
                    break;
                }                  
            }
            System.out.printf("\nLa risorsa della cover dell'album è: "+albumImageResource);
        }
        catch (org.jdom.JDOMException e) {
            System.out.printf(e.toString());
        }
        catch (java.io.IOException e) {
            System.out.printf(e.toString());
        }
    }
    
}
Come vedete il tutto è molto intuitivo, è possibile infatti per ogni tag ottenere un valore, un sottotag in particolare, o una lista di sottotag, o ancora la lista completa; e per ogni tag ottenere anche i parametri e il valore di ciascun parametro.

sabato 31 marzo 2012

Java: visualizzare gli elementi di una JTable come degli JCkeckBox

Se si vuole una JTable (una tabella swing di java) dove gli elementi (righe) selezionate sono visualizzate con un checkbox selezionato  e viceversa, con questo risultato:
è possibile modificare una proprietà della JTable tramite il metodo setDefaultRenderer(). Nel caso dello screenshot sopra, la tabella è divisa in un numero indeterminato di righe, e n° 6 colonne. La colonna interessata a visualizzare le celle con una checkbox è la prima, quindi il mio interesse è di modificare la colonna in questione. Per prima cosa definiamo la classe CheckBoxTableCellRenderer, ovvero una classe che eredita da JCheckBox e che si appoggià all'interfaccia JTableCellRenderer. Quest'ultima contiene solamente un metodo: getTableCellRendererComponent(), che noi definiamo a nostro piacere e che deve ritornare il componente (oggetto grafico) che vogliamo visualizzare nella casella, dunque il JCkeckBox

import javax.swing.JCheckBox;
import javax.swing.table.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.SwingConstants;
import java.awt.Component;
import java.awt.Insets;
import javax.swing.JTable;
import javax.swing.UIManager;

class CheckBoxTableCellRenderer
 extends JCheckBox
 implements TableCellRenderer {

 Border noFocusBorder;
 Border focusBorder;

 public CheckBoxTableCellRenderer() {
   super();
   setContentAreaFilled(true);  // sfondo opaco
   setBorderPainted(true);
   setHorizontalAlignment(SwingConstants.CENTER); (allineamento orizzontale centrato)
   setVerticalAlignment(SwingConstants.CENTER);   (allineamento verticale centrato)
 }

    @Override
 public Component getTableCellRendererComponent(JTable table, Object value,
                                                boolean isSelected,
                                                boolean hasFocus,
                                                int row, int column) {

   if(table == null) {
     //operazioni da fare nel caso la tabella non contenga alcun record
   }
   else { 
     if (isSelected) { //variabile locale che è vera se la riga è selezionata

         setForeground(table.getSelectionForeground());
         setBackground(table.getSelectionBackground());
     }
     else {

         setForeground(table.getForeground());
         setBackground(table.getBackground());
     }

     setEnabled(table.isEnabled());
     //questo pezzo di codice agisce sul bordo, per eliminare l'effetto "tasto"
     if (hasFocus) {
       if (focusBorder == null) {
         focusBorder = UIManager.getBorder("Table.focusCellHighlightBorder");
       }
       setBorder(focusBorder);
     }
     else {
       if (noFocusBorder == null) {
         if (focusBorder == null) {
           focusBorder = UIManager.getBorder("Table.focusCellHighlightBorder");
         }
         if (focusBorder != null) {
           Insets n = focusBorder.getBorderInsets(this);
           noFocusBorder = new EmptyBorder(n);
         }
       }
       setBorder(noFocusBorder);
     }

     //seleziona o meno il JCheckBox, in base al valore della cella (riga selezionata o meno)
     setSelected(Boolean.TRUE.equals(value));
   }
  //ritorna il JCheckBox 
   return this;
 }
}


Definita la classe CheckBoxTableCellRenderer, dobbiamo adesso adottarla nella JTable.
Supponiamo di avere una JTable di nome "table", quindi:



        TableColumnModel tcm = table.getColumnModel();
        TableColumn tc = tcm.getColumn(0); //la prima colonna è quella che ci interessa, in questo esempio
        tc.setCellRenderer(new CheckBoxTableCellRenderer());  

Fatto ciò, la prima colonna dunque apparirà come una lista di JCheckBox ordinati in verticale, proprio come nello screenshot sopra. Ma c'è ancora una cosa che manca: l'editor. Infatti se proviamo a modificare il valore di una JCheckBox (quindi il selezionare/deselezionare una riga), notiamo un'anomalia: compare la scritta "true" o "false". Perché? Perchè una JTable di default implementa una DefaultCellEditor, che mostra le celle come dei JTextBox, quindi mostra "true" o "false", in modo testo. Dunque un piccolo passaggio è doveroso:
tc.setCellEditor(new DefaultCellEditor(new JCheckBox()));
this.setCellSelectionEnabled(false);

Infatti (pace all'anima nostra), DefaultCellEditor prevede un costruttore con una JCheckBox. Mentre setCellSelectionEnabled() evita che si selezionino (con conseguente cambiamento del colore) le righe intere, infatti  a noi interessa distinguere se una riga è selezionata o meno guardando il JCheckBox.

Ricapitolando, i due passaggi fondamentali da compiere sulla colonna sono 2: modificare il suo renderer, e modificare il suo editor . Il renderer viene eseguito solamente quando la tabella viene disegnata, mentre il comportamento (editor) viene eseguito ogni qual volta modifichiamo il valore di una JCheckBox.
E' tutto.

Alberto

giovedì 29 marzo 2012

Convertitore UNIX Timestamp - Data in Java

Bene, per una mia applicazione Java avevo sempre questo problema del UNIX timestamp (ovvero il numero di secondi trascorsi dal 1 Gennaio 1970 alle ore 00:00:00), ovvero convertire una data in formato anno, mese, giorno, ore minuti e secondi in UNIX timestamp. Forse non ho cercato bene nella libreria di Java o forse non ho googlato per bene, ma una funzione che facesse ciò non l'ho trovata, solo timestamp dell'ora corrente (che non mi interessava).

Avevo urgentemente bisogno dell'algoritmo per calcolarlo che per pigrizia non ho mai scritto; adesso con il cambiamento all'ora legale è seguito un nuovo malfunzionamento del mio programma e quindi ho deciso di scriverlo una volta per tutte e condividerlo con chi ne avesse bisogno. 

L'algoritmo si compone di due parti: data una data (scusate il gioco di parole), la prima parte calcola il numero di secondi trascorsi fino al primo gennaio dell'anno corrente alle 00:00:00, la seconda parte aggiunge il "resto", ovvero il numero di secondi mancante. 

Specularmente, ho riciclato il suddetto algoritmo per fare il procedimento inverso, e ne è uscita fuori una bella classe che contiene i due metodi statici. 
Innanzitutto ho creato una classe ausiliaria Data, invece di utilizzare la java.util.Date.

package it.albe;

/**
 *
 * @author Alberto
 * 29/03/2012
 */
public class Data {
    public Data(int a,int m,int g, int o, int min, int sec){
        anno = a;
        mese = m;
        giorno = g;
        ore = o;
        minuti = min;
        secondi = sec;
    }
    public String toString(){
        String ms;
        switch(mese){
            case 1: ms = "Gennaio";break;
            case 2: ms = "Febbraio";break;
            case 3: ms = "Marzo";break;
            case 4: ms = "Aprile";break;
            case 5: ms = "Maggio";break;
            case 6: ms = "Giugno";break;
            case 7: ms = "Luglio";break;
            case 8: ms = "Agosto";break;
            case 9: ms = "Settembre";break;
            case 10: ms = "Ottobre";break;
            case 11: ms = "Novembre";break;
            case 12: ms = "Dicembre";break;
            default: ms="";
        }
        return String.valueOf(giorno)+" "+ms+" "+
                String.valueOf(anno)+" "+
                String.valueOf(ore)+":"+
                String.valueOf(minuti)+":"+
                String.valueOf(secondi);
    }
    public int anno;
    public int mese;
    public int giorno;
    public int ore;
    public int minuti;
    public int secondi;
}
Fatto ciò, ecco allora la classe Timestamp:

package it.albe;

/**
 *
 * @author Alberto
 * 29/03/2012
 */
public class Timestamp {
    public static long toUNIXtimestamp(Data data){
        long timestamp = 0;     
        for (int a=1970;a < data.anno;a++){ //anno
            if (a % 4 == 0 && (a % 100 != 0 || a % 400 == 0)){  //bisestile
                int m;
                for (m=1;m <= 12;m++)
                    switch(m){
                        case 1:
                        case 3:
                        case 5:
                        case 7:
                        case 8:
                        case 10:
                        case 12: {
                            int g;
                            for (g=1;g <= 31;g++)
                               timestamp+= 86400;
                        }break;
                        case 2: {
                            int g;
                            for (g=1;g <= 29;g++)
                               timestamp+= 86400;
                        }break;
                        case 4:
                        case 6:
                        case 9:
                        case 11:{
                            int g;
                            for (g=1;g <= 30;g++)
                               timestamp+= 86400;
                        }break;
                    } //switch                
            } //if
            else {      //non bisestile
                int m;
                for (m=1;m <= 12;m++)
                    switch(m){
                        case 1:
                        case 3:
                        case 5:
                        case 7:
                        case 8:
                        case 10:
                        case 12: {
                            int g;
                            for (g=1;g <= 31;g++)
                               timestamp+= 86400;
                        }break;
                        case 2:{
                            int g;
                            for (g=1;g <= 28;g++)
                               timestamp+= 86400;
                        }break;
                        case 4:
                        case 6:
                        case 9:
                        case 11:{
                            int g;
                            for (g=1;g <= 30;g++)
                               timestamp+= 86400;
                        }break;
                    } //switch
            } //else
        }    //for anno
        /***********************************************************/
        /*                   AGGIUNGO RESIDUO                      */
        /***********************************************************/
        if (data.anno % 4 == 0 && (data.anno % 100 != 0 || data.anno % 400 == 0)){
            int m;
            for (m=1;m < data.mese;m++)
                switch(m){
                    case 1:
                    case 3:
                    case 5:
                    case 7:
                    case 8:
                    case 10:
                    case 12: {
                        int g;
                        for (g=1;g <= 31;g++)
                           timestamp+= 86400;
                    }break;
                    case 2: {
                        int g;
                        for (g=1;g <= 29;g++)
                           timestamp+= 86400;
                    }break;
                    case 4:
                    case 6:
                    case 9:
                    case 11:{
                        int g;
                        for (g=1;g <= 30;g++)
                           timestamp+= 86400;
                    }break;
               } //switch  
           int g;
           for (g=1;g < data.giorno;g++)
               timestamp+= 86400;
           timestamp += data.secondi+data.minuti*60+data.ore*3600;             
        }
        else {
             int m;
            for (m=1;m < data.mese;m++)
                switch(m){
                    case 1:
                    case 3:
                    case 5:
                    case 7:
                    case 8:
                    case 10:
                    case 12: {
                        int g;
                        for (g=1;g <= 31;g++)
                           timestamp+= 86400;
                    }break;
                    case 2: {
                        int g;
                        for (g=1;g <= 28;g++)
                           timestamp+= 86400;
                    }break;
                    case 4:
                    case 6:
                    case 9:
                    case 11:{
                        int g;
                        for (g=1;g <= 30;g++)
                           timestamp+= 86400;
                    }break;
               } //switch  
           int g;
           for (g=1;g < data.giorno;g++)
               timestamp+= 86400;
           timestamp += data.secondi+data.minuti*60+data.ore*3600;  
        }
        return timestamp;
    }
    public static Data toDate(long Ptimestamp){
        int a;
        long timestamp = 0;
        for (a=1970;a < 2038;a++){ //anno
            if (a % 4 == 0 && (a % 100 != 0 || a % 400 == 0)){  //bisestile
                int m;
                for (m=1;m <= 12;m++)
                    switch(m){
                        case 1:
                        case 3:
                        case 5:
                        case 7:
                        case 8:
                        case 10:
                        case 12: {
                            int g;
                            int o;
                            int min;
                            int s;
                            for (g=1;g <= 31;g++)
                                for (o=0;o < 24;o++)
                                    for(min=0;min < 60;min++)
                                        for (s=0;s < 60;s++){
                                            timestamp++;
                                            if (Ptimestamp==timestamp){
                                                return new Data(a,m,g,o,min,s+1);
                                            
                                            }
                                        }
                        }break;
                        case 2: {
                            int g;
                            int o;
                            int min;
                            int s;
                            for (g=1;g <= 29;g++)
                                for (o=0;o < 24;o++)
                                    for(min=0;min < 60;min++)
                                        for (s=0;s < 60;s++){
                                            timestamp++;
                                            if (Ptimestamp==timestamp){
                                                return new Data(a,m,g,o,min,s+1);
                                            }
                                        }
                        }break;
                        case 4:
                        case 6:
                        case 9:
                        case 11:{
                            int g;
                            int o;
                            int min;
                            int s;
                            for (g=1;g <= 30;g++)
                                for (o=0;o < 24;o++)
                                    for(min=0;min < 60;min++)
                                        for (s=0;s < 60;s++){
                                            timestamp++;
                                            if (Ptimestamp==timestamp){
                                                return new Data(a,m,g,o,min,s+1);
                                            }
                                        }
                        }break;
                    } //switch                
            } //if
            else {      //non bisestile
                int m;
                for (m=1;m <= 12;m++)
                    switch(m){
                        case 1:
                        case 3:
                        case 5:
                        case 7:
                        case 8:
                        case 10:
                        case 12: {
                            int g;
                            int o;
                            int min;
                            int s;
                            for (g=1;g <= 31;g++)
                                for (o=0;o < 24;o++)
                                    for(min=0;min < 60;min++)
                                        for (s=0;s < 60;s++){
                                            timestamp++;
                                            if (Ptimestamp==timestamp){
                                                return new Data(a,m,g,o,min,s+1);
                                            }
                                        }
                        }break;
                        case 2:{
                            int g;
                            int o;
                            int min;
                            int s;
                            for (g=1;g <= 28;g++)
                                for (o=0;o < 24;o++)
                                    for(min=0;min < 60;min++)
                                        for (s=0;s < 60;s++){
                                            timestamp++;
                                            if (Ptimestamp==timestamp){
                                                return new Data(a,m,g,o,min,s+1);
                                            }
                                        }
                        }break;
                        case 4:
                        case 6:
                        case 9:
                        case 11:{
                            int g;
                            int o;
                            int min;
                            int s;
                            for (g=1;g <= 30;g++)
                                for (o=0;o < 24;o++)
                                    for(min=0;min < 60;min++)
                                        for (s=0;s < 60;s++){
                                            timestamp++;
                                            if (Ptimestamp==timestamp){
                                                return new Data(a,m,g,o,min,s+1);
                                            }
                                        }
                        }break;
                    } //switch
            } //else
        }    //for anno 
        return new Data(0,0,0,0,0,0);
    }
    
}
In pratica il metodo toUNIXtimestamp() nella prima parte fa un ciclo dove anno per anno controlla innanzitutto se è bisestile, e mese per mese controlla se è un 31 o un 28 o un 30, e poi giorno per giorno aumenta il timestamp di 86400 (numero di secondi in un giorno), mentre la seconda parte procede in maniera analoga tenendo conto della data di cui si vuol calcolare il timestamp.

L'altro metodo è analogo e non c'è nemmeno bisogno che lo spieghi.

Ed ecco un utilizzo esemplare di questa classe:


        Data data = new Data(2012,3,29,21,48,45); //29 marzo 2012 alle 21:48 e 45 secondi
        long ts = toUNIXtimestamp(data);
        System.out.print(ts+"\n");
        data = toDate(ts);
        System.out.print(data);

mercoledì 15 febbraio 2012

Scrobblit

Scrobblit è un programma scritto interamente in Java utile per scrobblare su last.fm le canzoni che noi ascoltiamo con iTunes (su Windows) o con Rythmbox (su linux).E' nato per una mia necessità di scrobblare le canzoni che ascolto col mio iPod, in alternativa alla versione ufficiale del software di last.fm che aveva cominciato a dare fastidiosi problemi.

Scrivo questo post per dare la possibilità a chi cerca su internet di avere un'alternativa al software di last fm, e anche per preannunciare il volere mettere open-source questo programma e quindi rilasciarne il codice sorgente. A breve posterò il progetto di source forge e chi vorrà entrarne a far parte è ben accetto, basta che contribuisca bene. Il programma non presenta grossi bug, quello più rilevante è il problema del fuso orario e del passaggio ora legale / ora solare.  E qualche miglioramento lo richiederebbe pure.

Comunque, la pagina da dove scaricare il programma è questa:
http://prodigious.altervista.org/Scrobblit/indexit.php

P.S. ci sono una decina di utilizzatori assidui del programma, compreso me :)

venerdì 9 dicembre 2011

GoTetris: la mia versione di Tetris scritta in Java


NOME: GoTetris
LINGUAGGIO: Java
PIATTAFORMA: Indipendente
LIBRERIE: N/D
PERIODO DI SVILUPPO: 19-20 Nov, 8-9 Dic 2011

Stavo iniziando già a lavorare per un altro programma, ma visto che proprio oggi ho completato Tetris dopo 4 giorni, ho deciso di illustrare qui come ho fatto a crearlo.
Il gioco è più che altro un esercizio personale per capire meglio i Task, gli oggetti Graphics e comunque per implementare un'approccio ludico; proprio per questo, una volta scritto, non l'ho affatto curato, l'interfaccia è scarna e si limita all'essenziale, ho risolto solo i bug più invasivi tralasciando quelli che si presentano più raramente.

Per accorciare: potete scaricare da qui il file .jar (ovviamente dovete avere installata la java virtual machine sul vostro sistema).I tasti per giocare sono A(sinistra), D(destra), S(ruota), Z(avanzamento veloce).

Il gioco, lo dico subito, contiene alcuni bug noti. Il più lampante è che ogni tanto scompaiono le cornici, o non si disegna lo sfondo, ma almeno è giocabile.  Per realizzarlo ho utilizzato le primitive grafiche di java, ovvero ho fatto un uso massiccio dell'oggetto Graphics della classe Canvas (da me riscritta).

La parte principale del gioco è stata realizzata creando un TimerTask, che grazie a un oggetto di tipo Timer ho invocato il metodo public void schedule(TimerTask task, long delay, long period) che mi permette di eseguire continuamente il TimerTask con un ritardo (periodo) di period millisecondi, variabili in base al livello del gioco (500 ms livello 1, 50 ms livello 10, 0 ms >10). Non ho messo un controllo su questa variabile...teoricamente se si supera il livello 10 dovrebbe diventare ingiocabile visto che non c'è alcun ritardo.

L'interfaccia viene curata continuamente dalla classe MyCanvas che eredita da java.awt.Canvas, mentre tutto il contenuto dell'area di gioco (quella coi quadratini) viene curato dalla classe Grid (griglia) che ho creato interamente io, servendomi di altre classi "satelliti" come BlockCollection o Block, per dirne due.
Ogni blocco non è altro che un array bidimensionale 4x4 di boolean e il suo colore è passato all'oggetto Graphics prima di disegnarlo.
Così per esempio, i famosi blocchi di tetris sono stati definiti così:

public static final boolean[][] I = {{false,true,false,false},{false,true,false,false},{false,true,false,false},{false,true,false,false}};
public static final boolean[][] O = {{false,false,false,false},{true,true,false,false},{true,true,false,false},{false,false,false,false}};
public static final boolean[][] J = {{true,true,true,false},{true,false,false,false},{false,false,false,false},{false,false,false,false}};
public static final boolean[][] L = {{true,true,true,false},{false,false,true,false},{false,false,false,false},{false,false,false,false}};
public static final boolean[][] S = {{true,true,false,false},{false,true,true,false},{false,false,false,false},{false,false,false,false}};
public static final boolean[][] T = {{true,true,true,false},{false,true,false,false},{false,false,false,false},{false,false,false,false}};
public static final boolean[][] Z = {{false,true,true,false},{true,true,false,false},{false,false,false,false},{false,false,false,false}};


Il sistema dei punteggi è un po' strambo...beh almeno è originale.
Il livello è dato da questa espressione: level = (punteggio/1000)+1; mentre il punteggio viene dato ogni volta che si scala una riga con l'espressione: punteggio+=level*100;




Ultima cosa, nel programma prima di istanziare l'oggetto grid è possibile modificare il numero delle righe e il numero nelle colonne a piacimento, nonché la spaziatura in pixel fra i quadratini e la grandezza in pixel di ogni singolo quadratino.

Il codice beh...sopra c'è il file jar quindi con un disassemblatore si potrebbe leggere tutto....bye!