giovedì 22 dicembre 2011

Sviluppo Python su Android con SL4A

In questo articolo vi parlerò di come collegare un dispositivo Android al vostro PC windows per utilizzare da remoto SL4A, un programma che invia istruzioni in diversi linguaggi scripting (fra cui Python) ad Android tramite chiamate RPC e permette di scrivere programmi o pezzi di script direttamente sul dispositivo.

Per prima cosa scaricare e installare SL4A sul dispositivo Android. Lo potete trovare qui:
http://code.google.com/p/android-scripting/downloads/list
file: sl4a_r4.apk (o ultima versione)

Scarichiamo anche l'ultimo interprete del linguaggio Python:
http://code.google.com/p/python-for-android/downloads/list
file: PythonForAndroid_r6.apk (o ultima versione)

Sul PC installate Android SDK:
http://developer.android.com/sdk/index.html

Sul PC avviate Android SDK Manager e installate il driver USB:


Sul device andare in: "Impostazioni" -> "Applicazioni" -> "Sviluppo" -> e spuntare l'opzione "Debug USB"


Sul PC aggiungete "C:\Program Files (x86)\Android\android-sdk\tools\" alla variabile ambiente di windows PATH


Dal prompt di windows digitare "gestione dispositivi" e su "Altri dispositivi" tasto destro e "Aggiornamento software driver"
fare cerca nel computer nella cartella: "C:\Program Files (x86)\Android\android-sdk\extras\google\usb_driver" (o dove avete installato l'sdk)


Se il dispositivo non viene riconosciuto fate proprietà -> dettagli e annotardi le 2 righe con gli hardware id:


Aprite il file "android_winusb.inf" per inserire gli hardware id annotati in precedenza:.

Per il tablet iconia A500 come il mio aggiungete le seguenti righe:

(sia alla fine sella sezione [Google.NTx86] che di [Google.NTamd64])
;
;Iconia A500
%SingleAdbInterface% = USB_Install, USB\VID_0502&PID_3325
%CompositeAdbInterface% = USB_Install, USB\VID_0502&PID_3325&MI_01

ripetete il riconoscimento del driver, tramite aggiornamento ed ora verrà trovato:


fate una prova lanciando il comando dal prompt di windows (con privilegi di amministratore): adb devices
dovrebbe restituirvi una stringa che rappresenta l'id del dispositivo connesso

Avviamo SL4A dal dispositivo Android. Ora dal menu del programma selezionate: View -> Interpreters
premiamo di nuovo il bottone menu, selezioniamo "start server". Selezioniamo "private" (public è usato per la connessione via wifi).

Ora siamo pronti alla connessione:
per prima cosa dobbiamo creare la seguente variabile d'ambiente per utente: AP_PORT con valore di default: 9999, poi abilitare il port forwarding


Nel caso abbiate un tablet cliccate sull'icona di SL4A nella tray e poi nel riquadro nero che compare per vedere a video il numero della porta usata dal server del dispositivo:


Aggiungiamo alla variabile d'ambiente PATH anche il percorso del file della shell Python Es.: ";C:\Python26"

Nella cartella lib della cartella dove avete installato Python Es.: "C:\Python26\Lib" salviamo il file "android.py"

Sul PC lanciamo un prompt windows come amministratore e digitiamo:
set AP_PORT=9999
adb forward tcp:9999 tcp:[numero di porta server SL4A]
python
Ora la vostra shell Python esegue i comandi sul dispositivo Android.

Ecco il codice per una piccola prova che stampa sul video del dispositivo il messaggio "Ciao sono il PC!"
import android  # dal file android.py che abbiamo aggiunto sul PC
droid = android.Android()
droid.makeToast("Ciao sono il PC!")

mercoledì 21 dicembre 2011

Appunti base relativi ai Design Patterns

Appunti sui Design patterns:
appunti design patterns
I design patterns sono suddivisi in queste tre principali categorie:

Creationals (Creazionali):
  • Permettono di astrarre il processo di creazione degli oggetti
  • Rendono un sistema indipendente da come i suoi oggetti sono stati creati, composti e rappresentati
  • Incapsulano la conoscenza sulle classi concrete che un sistema usa
  • Nascondono l'implementazione delle classi e della loro creazione
da immagine appunti design patterns
1.1, Creational
  1.1.1, AbstractFactory
    1.1.1.1, Crea oggetti che appartengono alla stessa famiglia e sono connessi o dipendenti tra loro
    1.1.1.2, Possibilità di utilizzare una famiglia diversa di prodotti a seconda della factory usata. L'interfaccia del client non cambia
  1.1.2, FactoryMethod
    1.1.2.1, Fornische un interfaccia per creare un oggetto ma sono le sottoclassi a decidere cosa istanziare
  1.1.3, Prototype
    1.1.3.1, Crea nuovi oggetti clonando quello base
  1.1.4,  Builder
    1.1.4.1, Separa la costruzione di un oggetto complesso dalla sua rappresentazione.  Lo stesso costruttore puó creare più rappresentazioni diverse
  1.1.5, Singleton 
    1.1.5.1, Fa in modo che una classe abbia una sola istanza e possa essere usata da tutti

Structural (Strutturali):
  • Sono dedicati alla composizione di classi e oggetti per creare delle strutture più grandi
  • Gli Structural class pattern utilizzando l'ereditarietà per creare interfacce o implementazioni
  • Gli Structural object pattern descrivono il modo in cui comporre gli oggetti per realizzare nuove funzionalità
da immagine appunti design patterns
1.2, Structural
  1.2.1, Proxy
    1.2.1.1, Inizializzare un oggetto solo quando viene chiamato il metodo
  1.2.2, Bridge
    1.2.2.1, Separa cosa si puó fare da cosa si fà
    1.2.2.2, Permette di eseguire la stessa operazione ma in maniera diversa a seconda del caso
    1.2.2.3, Costruisce un oggetto composto da varie parti.  Le parti che servono sono dinamiche a seconda del builder usato
  1.2.3, Facade
    1.2.3.1, Interfaccia di alto livello per richiamare sottosistemi diversi
  1.2.4, Adapter
    1.2.4.1, Adatta l'interfaccia di un elemento alla richiesta del client
  1.2.5, Decorator
    1.2.5.1, Aggiunge metodi all'oggetto in maniera dinamica
    1.2.5.2, Propone alternativa all'ereditarietà (anche multipla)
  1.2.6, Flyweight
    1.2.6.1, Condivide la parte riusabile di un oggetto
    1.2.6.2, La factory estra un oggetto dalla collezione interna o lo crea nuovo per risparmiare memoria, istanziando l'oggetto normalmente si accede alla parte non condivisa
  1.2.7, Composite
    1.2.7.1, Crea oggetti in strutture ad albero
    1.2.7.2, Esempio: il trapezio è composto da 2 triangoli e un rettangolo


Behavioral (Comportamentali):
  • Si focalizzano sul controllo di flusso degli oggetti
  • Descrivono le comunicazioni fra gli oggetti
  • Aiutano a valutare le responsabilità assegnate agli oggetti
  • Suggeriscono modi per incapsulare algoritmi dentro classi
da immagine appunti design patterns
1.3, Behavioral
  1.3.1, TemplateMethod
    1.3.1.1, Permette di variare una parte di un algoritmo e non toccare il resto
  1.3.2, Strategy
    1.3.2.1, Crea una classe con algoritmi intercambiabili ma interfaccia per richiamarli uguale
  1.3.3, Observer
    1.3.3.1, Crea eventi che si scatenano in tutti gli oggetti registrati quando viene notificato dall'oggetto principale
  1.3.4, Mediator
    1.3.4.1, Permette l'iterazione fra oggetti senza che uno abbia a che fare con l'altro
    1.3.4.2, L'oggetto principale incapsula l'iterazione fra gli oggetti contenuti
  1.3.5, State
    1.3.5.1, Cambia il comportamento a run-time dell'oggetto a seconda dello stato in cui si trova
  1.3.6, Interpreter
    1.3.6.1, Trasforma una sintassi, un linguaggio in entrata e interpretandone le espressioni produce un risultato in uscita
    1.3.6.2, L'interpreter precisa come valutare le frasi in una determinata lingua o linguaggio
  1.3.7, Visitor
    1.3.7.1, Rappresenta un operazione che puó essere eseguita sugli elementi di una struttura oggetto. 
    1.3.7.2, Permette di definire una nuova operazione senza modificare la struttura stessa
    1.3.7.3, Delega una funzionalità a una gerarchia di classi senza inquinarle
    1.3.7.4, Separa un algoritmo dalla struttura di oggetti compositi a cui è applicato
    1.3.7.5, Il visitor incapsula la funzionalità e la gerarchia viene dotata solo di un metodo per accedere ad uno di questi visitor
  1.3.8, Command
    1.3.8.1, Isola la porzione di codice che effettua un azione dal codice che ne richiede l'esecuzione; l'azione è incapsulata nell'oggetto command
    1.3.8.2, Utile da usare per associare azioni dell'interfaccia grafica(esempio click sul un bottone) al codice che esegue l'azione
  1.3.9, Iterator
    1.3.9.1, Fornisce un metodo per accedere agli oggetti di una collezione senza esporli direttamente
  1.3.10, Memento
    1.3.10.1, Estrae lo stato di un oggetto per ripristinarlo successivamente (come undo)
  1.3.11, Chain of responsability
    1.3.11.1, Separa oggetti che fanno le richieste da quelli che le gestiscono
    1.3.11.2, Usa un determinato oggetto che si incarica di soddisfare la richiesta effettuata

venerdì 9 dicembre 2011

Factory Method Design Pattern in pratica

Il Factory Method, fa parte dei creational patterns, esso consente di utilizzare un'interfaccia per la creazione di un oggetto, ma sono le sottoclassi a decidere quale classe istanziare.
L’obbiettivo principale è l’estensibilità, consente di istanziare un oggetto senza specificare una classe.
Il Factory Method è spesso utilizzato in applicazioni che:
  • necessitano che la creazione o la rappresentazione di oggetti sia nascosta ed indipendente dalla struttura principale.
  • gestiscono, mantengono, o manipolano collezioni di oggetti diverse, ma con molte caratteristiche in comune.
  • se il sistema principale viene modificato si possono modificare facilmente anche le caratteristiche comuni fra gli oggetti
  • forniscono una libreria di classi in cui è visibile solo l’interfaccia, ma non l’implementazione della classe
Ci sono 3 regole principali che il pattern Factory Method deve rispettare:
  1. Il metodo crea un nuovo oggetto
  2. Il metodo ritorna una classe astratta o un interfaccia
  3. La classe astratta o l’interfaccia viene implementata da più classi

Ora vediamo un piccolo esempio di implementazione per capire meglio come funziona il pattern Factory Method nei seguenti linguaggi:
(questi ultimi due comunque non supportano interfacce o classi astratte, quindi bisogna prestare la massima attenzione all’implementazione, magari usando una buona convenzione sui nomi delle classi e dei metodi, in maniera di evitare di utilizzare classi o metodi sbagliati per distrazione)

Diagramma UML:
In un nuovo progetto di tipo Console aggiungo il file “Persona” e creo la classe persona (questa classe sarà usata anche nei miei prossimi post sui design patterns):
//C#
using System;

namespace Netrudy.Patterns
{
    //Classe che rappresenta una persona fisica
    class Persona
    {
        //Costruttore
        public Persona(string nome, string cognome)
        {
            this.Nome = nome;
            this.Cognome = cognome;
        }

        //Nome
        public String Nome { get; set; }

        //Cognome
        public String Cognome { get; set; }
    }
}
'VB.NET
Namespace Netrudy.Patterns
    'Classe che rappresenta una persona fisica
    Class Persona
        'Costruttore
        Public Sub New(nome As String, cognome As String)
            Me.Nome = nome
            Me.Cognome = cognome
        End Sub

        'Nome
        Public Property Nome() As [String]
            Get
                Return m_Nome
            End Get
            Set(value As [String])
                m_Nome = value
            End Set
        End Property
        Private m_Nome As [String]

        'Cognome
        Public Property Cognome() As [String]
            Get
                Return m_Cognome
            End Get
            Set(value As [String])
                m_Cognome = value
            End Set
        End Property
        Private m_Cognome As [String]
    End Class
End Namespace
//Java
package Netrudy.Patterns;

//Classe che rappresenta una persona fisica
public class Persona
{
    //Costruttore
    public Persona(String nome, String cognome)
    {
        this.setNome(nome);
        this.setCognome(cognome);
    }

    //Nome
    private String privateNome;
    public final String getNome()
    {
        return privateNome;
    }
    public final void setNome(String value)
    {
        privateNome = value;
    }

    //Cognome
    private String privateCognome;
    public final String getCognome()
    {
        return privateCognome;
    }
    public final void setCognome(String value)
    {
        privateCognome = value;
    }
}
//C++/CLI file .h
#pragma once

using namespace System;

namespace Netrudy
{
    namespace Patterns
    {
        //Classe che rappresenta una persona fisica
        private ref class Persona
        {
            //Costruttore
        public:
            Persona(String ^nome, String ^cognome);

            //Nome
            property String ^Nome;

            //Cognome
            property String ^Cognome;
        };
    }
}

//file .cpp
#include "Persona.h"

using namespace System;
namespace Netrudy
{
    namespace Patterns
    {

        Persona::Persona(String ^nome, String ^cognome)
        {
            this->Nome = nome;
            this->Cognome = cognome;
        }
    }
}
//C++ Nativo file .h
#pragma once

#include <string>

namespace Netrudy
{
    namespace Patterns
    {
        //Classe che rappresenta una persona fisica
        class Persona
        {
            //Costruttore
        public:
            Persona(const std::string &nome, const std::string &cognome);

            //Nome
            private:
                std::string privateNome;
            public:
                std::string getNome();
                void setNome(const std::string &value);

            //Cognome
            private:
                std::string privateCognome;
            public:
                std::string getCognome();
                void setCognome(const std::string &value);
        };
    }
}

//file .cpp
#include "Persona.h"

namespace Netrudy
{
    namespace Patterns
    {

        Persona::Persona(const std::string &nome, const std::string &cognome)
        {
            this->Nome = nome;
            this->Cognome = cognome;
        }

        std::string Persona::getNome()
        {
            return privateNome;
        }

        void Persona::setNome(const std::string &value)
        {
            privateNome = value;
        }

        std::string Persona::getCognome()
        {
            return privateCognome;
        }

        void Persona::setCognome(const std::string &value)
        {
            privateCognome = value;
        }
    }
}
#Python
"""Classe che rappresenta una persona fisica"""
class Persona(object):
    
    #Costruttore
    def __init__(self, nome, cognome):
        self._nome = nome
        self._cognome = cognome

    #Nome
    def getNome(self):
        return self._nome

    def setNome(self, value):
        self._nome = value

    Nome = property(getNome, setNome)

    #Cognome
    def getCognome(self):
        return self._cognome

    def setCognome(self, value):
        self._cognome = value

    Cognome = property(getCognome, setCognome)
//Javascript
//Classe che rappresenta una persona fisica
//Costruttore
Netrudy.Patterns._persona = function Netrudy_Patterns__persona(nome, cognome) {
    this.set_nome(nome);
    this.set_cognome(cognome);
}
Netrudy.Patterns._persona.prototype = {
    //Nome
    _nome: null,
    
    get_nome: function Netrudy_Patterns__persona$get_nome() {
        return this._nome;
    },
    set_nome: function Netrudy_Patterns__persona$set_nome(value) {
        this._nome = value;
        return value;
    },
    
    //Cognome
    _cognome: null,
    
    get_cognome: function Netrudy_Patterns__persona$get_cognome() {
        return this._cognome;
    },
    set_cognome: function Netrudy_Patterns__persona$set_cognome(value) {
        this._cognome = value;
        return value;
    }
}
N.B.: Per Javascript ho usato Script#: http://projects.nikhilk.net/ScriptSharp alcune funzioni utilizzano parte di codice della libreria “mscorlib.js” di Script#, che è un misto di AJAX e funzioni di .NET Framework riadattate al Javascript (per esempio le collezioni Enumerable).
Aggiungiamo il file “FactoryMethod” e iniziamo a scrivere il seguente codice:
Dichiaro gli oggetti dipendente e datore di lavoro che derivano da persona (e rappresentano delle persone fisiche) questi sono i nostri oggetti nascosti:
//C#
//Personale di tipo: dipendente
class ConcreteDipendente : Persona
{
    public ConcreteDipendente(string nome, string cognome)
        : base(nome, cognome) {}
}

//Personale di tipo: datore di lavoro
class ConcreteDatoreDiLavoro : Persona
{
    public ConcreteDatoreDiLavoro(string nome, string cognome)
        : base(nome, cognome) {}
}
'VB.NET
'Personale di tipo: dipendente
Class ConcreteDipendente
    Inherits Persona
    Public Sub New(nome As String, cognome As String)
        MyBase.New(nome, cognome)
    End Sub
End Class

'Personale di tipo: datore di lavoro
Class ConcreteDatoreDiLavoro
    Inherits Persona
    Public Sub New(nome As String, cognome As String)
        MyBase.New(nome, cognome)
    End Sub
End Class
//Java
//Personale di tipo: datore di lavoro
public class ConcreteDatoreDiLavoro extends Persona
{
    public ConcreteDatoreDiLavoro(String nome, String cognome)
    {
        super(nome, cognome);
    }
}

//Personale di tipo: dipendente
public class ConcreteDipendente extends Persona
{
    public ConcreteDipendente(String nome, String cognome)
    {
        super(nome, cognome);
    }
}
//C++/CLI file .h
//Personale di tipo: dipendente
private ref class ConcreteDipendente : Persona
{
public:
    ConcreteDipendente(String ^nome, String ^cognome);
};

//Personale di tipo: datore di lavoro
private ref class ConcreteDatoreDiLavoro : Persona
{
public:
    ConcreteDatoreDiLavoro(String ^nome, String ^cognome);
};

//file .cpp
ConcreteDipendente::ConcreteDipendente(String ^nome, String ^cognome) : Persona(nome, cognome)
{
}

ConcreteDatoreDiLavoro::ConcreteDatoreDiLavoro(String ^nome, String ^cognome) : Persona(nome, cognome)
{
}
//C++ Nativo file .h
//Personale di tipo: dipendente
class ConcreteDipendente : public Persona
{
public:
    ConcreteDipendente(const std::string &nome, const std::string &cognome);
};

//Personale di tipo: datore di lavoro
class ConcreteDatoreDiLavoro : public Persona
{
public:
    ConcreteDatoreDiLavoro(const std::string &nome, const std::string &cognome);
};

// file .cpp
ConcreteDipendente::ConcreteDipendente(const std::string &nome, const std::string &cognome) : Persona(nome, cognome)
{
}

ConcreteDatoreDiLavoro::ConcreteDatoreDiLavoro(const std::string &nome, const std::string &cognome) : Persona(nome, cognome)
{
}
#Python
#Personale di tipo: dipendente
class ConcreteDipendente(Persona):

    def __init__(self, nome, cognome):
        Persona.__init__(self, nome, cognome)
        
#Personale di tipo: datore di lavoro
class ConcreteDatoreDiLavoro(Persona):

    def __init__(self, nome, cognome):
        Persona.__init__(self, nome, cognome)
//Javascript
//Personale di tipo: dipendente
Netrudy.Patterns._concreteDipendente = function Netrudy_Patterns__concreteDipendente(nome, cognome) {
    Netrudy.Patterns._concreteDipendente.initializeBase(this, [ nome, cognome ]);
}
//Personale di tipo: datore di lavoro
Netrudy.Patterns._concreteDatoreDiLavoro = function Netrudy_Patterns__concreteDatoreDiLavoro(nome, cognome) {
    Netrudy.Patterns._concreteDatoreDiLavoro.initializeBase(this, [ nome, cognome ]);
}
Come possiamo notare se c’è un costruttore nella classe base (persona) è necessario implementarlo anche nelle classi derivate.
Queste due classi appena create sono quelle concrete, cioè quelle con i campi e i metodi delle persone, e verranno create o meno a seconda di cosa scriveremo nel metodo di creazione FactoryMethod che implementeremo derivando la nostra nuova classe dalla seguente classe astratta:
//C#
//Classe astratta che rappresenta il personale dell'azienda
abstract class PersonaleAziendaCreator
{
    //Costruttore che chiama il metodo astratto
    //FactoryMethod
    //che verrà implementato nella classe figlia
    protected PersonaleAziendaCreator()
    {
        Persone = new List();
        this.FactoryMethod();
    }

    //Metodo astratto da implementare
    protected abstract void FactoryMethod();

    //Lista del personale aziendale (che sarà legato
    //alla categoria della classe figlia)
    public List Persone { get; protected set; }
}
'VB.NET
'Classe astratta che rappresenta il personale dell'azienda
MustInherit Class PersonaleAziendaCreator
    'Costruttore che chiama il metodo astratto FactoryMethod
    'che verrà implementato nella classe figlia
    Protected Sub New()
        Persone = New List(Of Persona)()
        Me.FactoryMethod()
    End Sub

    'Metodo astratto da implementare
    Protected MustOverride Sub FactoryMethod()

    'Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
    Public Property Persone() As List(Of Persona)
        Get
            Return m_Persone
        End Get
        Protected Set(value As List(Of Persona))
            m_Persone = Value
        End Set
    End Property
    Private m_Persone As List(Of Persona)
End Class
//Java
//Classe astratta che rappresenta il personale dell'azienda
public abstract class PersonaleAziendaCreator
{
    //Costruttore che chiama il metodo astratto FactoryMethod
    //che verrà implementato nella classe figlia
    protected PersonaleAziendaCreator()
    {
        setPersone(new java.util.ArrayList<Persona>());
        this.FactoryMethod();
    }

    //Metodo astratto da implementare
    protected abstract void FactoryMethod();

    //Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
    private java.util.ArrayList<Persona> privatePersone;
    public final java.util.ArrayList<Persona> getPersone()
    {
        return privatePersone;
    }
    protected final void setPersone(java.util.ArrayList<Persona> value)
    {
        privatePersone = value;
    }
}
//C++/CLI file .h
//Classe astratta che rappresenta il personale dell'azienda
private ref class PersonaleAziendaCreator abstract
{
    //Costruttore che chiama il metodo astratto FactoryMethod
    //che verrà implementato nella classe figlia
protected:
    PersonaleAziendaCreator();

    //Metodo astratto da implementare
    virtual void FactoryMethod() abstract;

    //Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
public:
    property List<Persona^> ^Persone;
};

//file .cpp
PersonaleAziendaCreator::PersonaleAziendaCreator()
{
    Persone = gcnew List<Persona^>();
    this->FactoryMethod();
}
//C++ Nativo file .h
//Classe astratta che rappresenta il personale dell'azienda
class PersonaleAziendaCreator
{
    //Costruttore che chiama il metodo astratto FactoryMethod
    //che verrà implementato nella classe figlia
protected:
    PersonaleAziendaCreator();

    //Metodo astratto da implementare
    virtual void FactoryMethod() = 0;

    //Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
    private:
        std::vector<Persona*> privatePersone;
    public:
        std::vector<Persona*> getPersone();
        void setPersone(std::vector<Persona*> value);
};

//file .cpp
PersonaleAziendaCreator::PersonaleAziendaCreator()
{
    Persone = std::vector<Persona*>();
    this->FactoryMethod();
}

std::vector<Persona*> PersonaleAziendaCreator::getPersone()
{
    return privatePersone;
}

void PersonaleAziendaCreator::setPersone(std::vector<Persona*> value)
{
    privatePersone = value;
}
#Python
"""Classe astratta che rappresenta il personale dell'azienda"""
#Python non supporta interfacce o classi astratte quindi utilizziamo il seguente workaround
class PersonaleAziendaCreator(object):

def __init__(self):
    self._persone = []
    self.FactoryMethod()

#workaround per metodo astratto
def FactoryMethod(self, arg):
    raise NotImplementedError("Metodo astratto!")

def getPersone(self):
    return self._persone

def setPersone(self, value):
    self._persone = value

Persone = property(getPersone, setPersone)
//Javascript
//Classe che rappresenta il personale dell'azienda
Netrudy.Patterns._personaleAziendaCreator = function Netrudy_Patterns__personaleAziendaCreator() {
    this.set_persone([]);
    //Metodo astratto da implementare
    this.factoryMethod();
}
Netrudy.Patterns._personaleAziendaCreator.prototype = {
    _persone: null,
    
    //Lista del personale aziendale (che sarà legato alla categoria della classe figlia)
    get_persone: function Netrudy_Patterns__personaleAziendaCreator$get_persone() {
        return this._persone;
    },
    set_persone: function Netrudy_Patterns__personaleAziendaCreator$set_persone(value) {
        this._persone = value;
        return value;
    }
}
Ora creiamo le classi di creazione del personale dell’azienda che implementeranno il FactoryMethod poiché derivando dalla classe base PersonaleAziendaCreator:
//C#
//Classe che si occupa di creare i dipendenti
//dell'azienda
class ConcreteCreatorDipendente : PersonaleAziendaCreator
{
    protected override void FactoryMethod()
    {
        Persone.Add(new ConcreteDipendente("Luigi", "Bross"));
        Persone.Add(new ConcreteDipendente("Toad", "Fungo"));
    }
}



//Classe che si occupa di creare i datori di lavoro 
//dell'azienda
class ConcreteCreatorDatoreDiLavoro : PersonaleAziendaCreator
{
    protected override void FactoryMethod()
    {
        Persone.Add(new ConcreteDatoreDiLavoro("Mario", "Boss"));
    }
}
'VB.NET
'Classe che si occupa di creare i dipendenti dell'azienda
Class ConcreteCreatorDipendente
    Inherits PersonaleAziendaCreator
    Protected Overrides Sub FactoryMethod()
        Persone.Add(New ConcreteDipendente("Luigi", "Bross"))
        Persone.Add(New ConcreteDipendente("Toad", "Fungo"))
    End Sub
End Class

'Classe che si occupa di creare i datori di lavoro dell'azienda
Class ConcreteCreatorDatoreDiLavoro
    Inherits PersonaleAziendaCreator
    Protected Overrides Sub FactoryMethod()
        Persone.Add(New ConcreteDatoreDiLavoro("Mario", "Boss"))
    End Sub
End Class
//Java
//Classe che si occupa di creare i dipendenti dell'azienda
public class ConcreteCreatorDipendente extends PersonaleAziendaCreator
{
    @Override
    protected void FactoryMethod()
    {
        getPersone().add(new ConcreteDipendente("Luigi", "Bross"));
        getPersone().add(new ConcreteDipendente("Toad", "Fungo"));
    }
}

//Personale di tipo: datore di lavoro
public class ConcreteDatoreDiLavoro extends Persona
{
    public ConcreteDatoreDiLavoro(String nome, String cognome)
    {
        super(nome, cognome);
    }
}
//C++/CLI file .h
//Classe che si occupa di creare i dipendenti dell'azienda
private ref class ConcreteCreatorDipendente : PersonaleAziendaCreator
{
protected:
    virtual void FactoryMethod() override;
};

//Classe che si occupa di creare i datori di lavoro dell'azienda
private ref class ConcreteCreatorDatoreDiLavoro : PersonaleAziendaCreator
{
protected:
    virtual void FactoryMethod() override;
};

//file .cpp
void ConcreteCreatorDipendente::FactoryMethod()
{
    Persone->Add(gcnew ConcreteDipendente("Luigi", "Bross"));
    Persone->Add(gcnew ConcreteDipendente("Toad", "Fungo"));
}

void ConcreteCreatorDatoreDiLavoro::FactoryMethod()
{
    Persone->Add(gcnew ConcreteDatoreDiLavoro("Mario", "Boss"));
}
//C++ Nativo file .h
//Classe che si occupa di creare i dipendenti dell'azienda
class ConcreteCreatorDipendente : public PersonaleAziendaCreator
{
protected:
    virtual void FactoryMethod();
};

//Classe che si occupa di creare i datori di lavoro dell'azienda
class ConcreteCreatorDatoreDiLavoro : public PersonaleAziendaCreator
{
protected:
    virtual void FactoryMethod();
};

//file .cpp
void ConcreteCreatorDipendente::FactoryMethod()
{
    Persone->Add(new ConcreteDipendente("Luigi", "Bross"));
    Persone->Add(new ConcreteDipendente("Toad", "Fungo"));
}

void ConcreteCreatorDatoreDiLavoro::FactoryMethod()
{
    Persone->Add(new ConcreteDatoreDiLavoro("Mario", "Boss"));
}
#Python
#Classe che si occupa di creare i dipendenti dell'azienda
class ConcreteCreatorDipendente(PersonaleAziendaCreator):

    def FactoryMethod(self):
        self.Persone.append(ConcreteDipendente("Luigi", "Bross"))
        self.Persone.append(ConcreteDipendente("Toad", "Fungo"))

#Classe che si occupa di creare i datori di lavoro dell'azienda
class ConcreteCreatorDatoreDiLavoro(PersonaleAziendaCreator):

    def FactoryMethod(self):
        self.Persone.append(ConcreteDatoreDiLavoro("Mario", "Boss"))
//Javascript
//Classe che si occupa di creare i dipendenti dell'azienda


Netrudy.Patterns._concreteCreatorDipendente = function Netrudy_Patterns__concreteCreatorDipendente() {
    Netrudy.Patterns._concreteCreatorDipendente.initializeBase(this);
}
Netrudy.Patterns._concreteCreatorDipendente.prototype = {
    
    factoryMethod: function Netrudy_Patterns__concreteCreatorDipendente$factoryMethod() {
        this.get_persone().add(new Netrudy.Patterns._concreteDipendente('Luigi', 'Bross'));
        this.get_persone().add(new Netrudy.Patterns._concreteDipendente('Toad', 'Fungo'));
    }
}

//Classe che si occupa di creare i datori di lavoro dell'azienda
Netrudy.Patterns._concreteCreatorDatoreDiLavoro = function Netrudy_Patterns__concreteCreatorDatoreDiLavoro() {
    Netrudy.Patterns._concreteCreatorDatoreDiLavoro.initializeBase(this);
}
Netrudy.Patterns._concreteCreatorDatoreDiLavoro.prototype = {
    
    factoryMethod: function Netrudy_Patterns__concreteCreatorDatoreDiLavoro$factoryMethod() {
        this.get_persone().add(new Netrudy.Patterns._concreteDatoreDiLavoro('Mario', 'Boss'));
    }
}
A questo punto proviamo il programma implementando il metodo main del nostro progetto:
//C#
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator creaDipendenti = new ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator creaDatori = new ConcreteCreatorDatoreDiLavoro();

//Unisco il gruppo di persone create
List persone = new List(creaDatori.Persone.Union(creaDipendenti.Persone));

//Per ogni persona scrive a video il tipo di oggetto 
//della persona e il nome
foreach (Persona persona in persone)
{
    Console.WriteLine("Persona (di tipo: {0}): {1}", persona.GetType(), persona.Nome);
}
'VB.NET
'Istanzio la classe per creare i dipendenti
Dim creaDipendenti As PersonaleAziendaCreator = New ConcreteCreatorDipendente()
'Istanzio la classe per creare i datori di lavoro
Dim creaDatori As PersonaleAziendaCreator = New ConcreteCreatorDatoreDiLavoro()

'Unisco il gruppo di persone create
Dim persone As New List(Of Persona)(creaDatori.Persone.Union(creaDipendenti.Persone))

'Per ogni persona scrive a video il tipo di oggetto della persona e il nome
For Each persona As Persona In persone
    Console.WriteLine("Persona (di tipo: {0}): {1}", persona.[GetType](), persona.Nome)
Next
//Java
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator creaDipendenti = new ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator creaDatori = new ConcreteCreatorDatoreDiLavoro();

//Unisco il gruppo di persone create
java.util.ArrayList<Persona> persone = new java.util.ArrayList<Persona>(creaDatori.getPersone().Union(creaDipendenti.getPersone()));

//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for (Persona persona : persone)
{
    System.out.println("Persona (di tipo: {0}): {1}", persona.getClass(), persona.getNome());
}
//C++/CLI file .cpp
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator ^creaDipendenti = gcnew ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator ^creaDatori = gcnew ConcreteCreatorDatoreDiLavoro();

//Unisco il gruppo di persone create
List<Persona^> ^persone = gcnew List<Persona^>(creaDatori->Persone->Union(creaDipendenti->Persone));

//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for each (Persona ^persona in persone)
{
    Console::WriteLine("Persona (di tipo: {0}): {1}", persona->GetType(), persona->Nome);
}
//C++ Nativo .cpp
//Istanzio la classe per creare i dipendenti
PersonaleAziendaCreator *creaDipendenti = new ConcreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
PersonaleAziendaCreator *creaDatori = new ConcreteCreatorDatoreDiLavoro();

//Unisco il gruppo di persone create
std::vector<Persona*> persone = std::vector<Persona*>(creaDatori->Persone->Union(creaDipendenti->Persone));

//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for (std::vector<Persona*>::const_iterator persona = persone.begin(); persona != persone.end(); ++persona)
{
    std::cout << "Persona (di tipo: " << (*persona)->GetType() << "): " << (*persona)->Nome << std::endl;
}
#Python
#Istanzio la classe per creare i dipendenti
creaDipendenti = ConcreteCreatorDipendente()
#Istanzio la classe per creare i i datori di lavoro
creaDatori = ConcreteCreatorDatoreDiLavoro()

#Unisco il gruppo di persone create
persone = list(set(creaDipendenti.getPersone()) | set(creaDatori.getPersone()))

#Per ogni persona scrive a video il tipo di oggetto della persona e il nome
for persona in persone:
    print "Persona (di tipo: {0})): {1}".format(type(persona), persona.Nome)
//Javascript
//Istanzio la classe per creare i dipendenti
var creaDipendenti = new Netrudy.Patterns._concreteCreatorDipendente();
//Istanzio la classe per creare i datori di lavoro
var creaDatori = new Netrudy.Patterns._concreteCreatorDatoreDiLavoro();
//Unisco il gruppo di persone create
var persone = creaDipendenti.get_persone().concat(creaDatori.get_persone());
//Per ogni persona scrive a video il tipo di oggetto della persona e il nome
var $enum1 = ss.IEnumerator.getEnumerator(persone);
while ($enum1.moveNext()) {
    var persona = $enum1.current;
    ss.Debug.writeln(String.format('Persona (di tipo: {0}): {1}', Type.getInstanceType(persona), persona.get_nome()));
}

lunedì 5 dicembre 2011

Istallazione Windows 8 Developer Preview with developer tools 64bit su VMWare Workstation 8

Per prima cosa scarichiamo l’immagine ISO da qui: Windows 8 Developer Preview with developer tools English, 64-bit (x64)
Avviamo VMware Workstation, e selezioniamo dal menu file, nuova, virtual machine, in questo modo partirà il wizard di creazione.

05-12-2011 11-08-22
Scegliamo tipical e premiamo next.
A questo punto selezioniamo installer disk image file (iso) e selezioniamo il percorso del file dove si trova la nostra immagine scaricata:

05-12-2011 15-56-04
Nella fase successiva selezioniamo Miscrosoft Windows dalla lista dei sistemi operativi e Windows 7 64-bit dalla lista delle versioni:

05-12-2011 15-58-14
Lasciamo libero il product key di windows e scriviamo una nostra password:

05-12-2011 16-00-51b
Diamo un nome alla nostra macchina virtuale e selezioniamo un percorso dove verranno salvati i files:

05-12-2011 16-05-41
Selezioniamo la quantità di memoria del disco rigido virtuale, desiderata (io avendo spazio ho messo 40gb, ma credo bastino 20), e se vogliamo che il disco sia diviso in più files o su uno solo:

05-12-2011 16-06-25
A questo punto rileggiamo se abbiamo impostato tutto correttamente e premiamo Finish per fare partire la macchina virtuale.

05-12-2011 16-07-22

Se è andato tutto bene dovreste vedere partire l’installazione di Windows 8:
05-12-2011 16-08-33
Ad un certo punto però otterrete questo messaggio d’errore:

05-12-2011 16-10-14
Spegnete la macchina virtuale, andate nelle menu delle impostazioni (VM –> Settings), e rimuovete il Floppy dall’elenco dei devices:

05-12-2011 16-16-25
Date OK e riavviate la macchina virtuale.
Ora l’installazione partirà correttamente e arriverete alla finestra di selezione delle opzioni internazionali del sitema operativo.
Come prima opzione lasciamo “Language to install”: English (è anche l’unica selezionabile).
Come “Time and currency format”, possiamo impostare Italiano.
Come “Keyboar or input method”, possiamo impostare Italiano (se abbiamo una tastiera italiana naturalmente).

05-12-2011 16-20-17
Portiamo a termine i vari passaggi successivi come sempre e abbiamo finito.

Libri gratis per programmatori

Qui, trovate i libri della rivista IO Programmo, degli ultimi 2,3 anni, formato PDF: “Libri di programmazione gratis”, c'è un po’di tutto per .NET, Java, C++, Python, SQL Server.


Conversione di un numero in colonna Excel

Ecco il codice per convertire un numero nell'indice alfanumerico di una colonna Excel:
public static class ExcelFunc
{
    public static string ConvertToLetter(int colIndex)
    {
        string ret = string.Empty;
        var alpha = colIndex/27;
        var remainder = colIndex-(alpha*26);
        if (alpha > 0)
            ret = Char.ConvertFromUtf32(alpha+64);
        if (remainder > 0)
                ret += Char.ConvertFromUtf32(remainder+64);
        return ret;
    }
}

Convertire un click in doubleclick

Utilzzando un controllo di terze parti, mi sono accorto che il suo produttore non aveva implementato l’evento double click in un punto che secondo me era essenziale, allora con qualche riga di codice mi sono trasformato un evento click in double click:
private DateTime mTimeToDoubleC = DateTime.Now;

private void button1_Click(object sender, EventArgs e)
{
    DateTime adesso = DateTime.Now;
    if ((adesso - mTimeToDoubleC) < new TimeSpan(0, 0, 0, 0, SystemInformation.DoubleClickTime))
    {
        //Esegui il metodo per il double click...
    }
    else
    {
        //Esegui il metodo per il click normale...
    }
}
Come si può vedere utilizzando la proprietà SystemInformation.DoubleClickTime ottengo un double click perciso come impostato nel sistema.

Windows Live Mail – Correttore in Italiano

Ecco come fare per aggiungere la correzione ortografica in Italiano a Windows Live Mail.
Requisiti:
aver installato MSOffice con incluso controllo ortografico e grammaticale in Italiano.

Cosa fare:
creare una directory 'prf0010' (notare il codice 0010. Se fosse stato per la lingua tedesca sarebbe dovuta essere 'prf0007', per l'inglese 'prf0009' etc.) in 'C:\Users\\AppData\Local\Microsoft\Windows Live Mail\Proof'
creare la directory '1' dentro prf0010
copiare i file 'MSSP3IT.DLL' e 'MSSP3IT.LEX' presenti di norma in 'C:\Program Files\Common Files\microsoft shared\Proof' dentro 'C:\Users\\AppData\Local\Microsoft\Windows Live Mail\Proof\prf0010\1\'
creare un file di testo in 'prf0010\1\' da rinominare poi 'spell.ini' (notare l'estensione INI) con dentro (senza lasciare righe vuote all'inizio):
Codice:
[Spellchecker]
Engine=MSSP3IT.DLL
Lex=MSSP3IT.LEX
Lang=1040(premere RETURN per creare una nuova linea vuota subito alla fine di '...1040' e salvare il file)
Riassumendo alla fine avrete: in C:\Users\\AppData\Local\Microsoft\Windows Live Mail\Proof\prf0010\1\ i 2 file (DLL e LEX) + il file spell.ini.
Fine.
A questo punto riaprendo WLM e andando alla pagina del correttore ortografico nelle preferenze di WLM vedrete apparire finalmente l'Italiano installato (e anche la spunta su 'controlla ortografia nella lingua corrente di input' per cambiare lingua e vocabolario al volo tramite la Barra delle lingue di Vista funzionerà a dovere).

Evento minimize e forms ridotti a icona nella Tray

Ecco il codice per gestire una form che passa dalla visualizzazione normale alla tray bar e dopo avere fatto doppio click sull’icona ritorna alla posizione iniziale in primo piano:

Come prima cosa aggiungiamo a design il componente “NotifyIcon” e lo chiamiamo “notifyIcon”.
Impostiamo la proprietà visible a false.
Siccome non abbiamo un evento minimized, implementiamo il seguente codice usando l’evento Resize della form:
private void FrmMain_Resize(object sender, EventArgs e)
{
    if (System.Windows.Forms.FormWindowState.Minimized == WindowState)
    {
        this.Hide();
        notifyIcon.Visible = true;
    }
}
Ora implementiamo il seguente codice per l’evento DoubleClick sulla notifyIcon e il gioco è fatto:
private void notifyIcon_DoubleClick(object sender, EventArgs e)
{
    this.Show();
    this.WindowState = FormWindowState.Normal;
    notifyIcon.Visible = false;
}

Localizzare i mesi dell'anno

Per ottenere i nomi dei mesi dell'anno localizzati in base alla lingua corrente del vostro programma potete usare questa semplice funzione:
//C#
int iMonth = 1; //Numero intero che corrisponde al mese da localizzare (in questo caso Gennaio)
string month = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(iMonth);
'VB.NET
Dim iMonth As Integer = 1
'Numero intero che corrisponde al mese da localizzare (in questo caso Gennaio)
Dim month As String = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(iMonth)

venerdì 2 dicembre 2011

Disabilitare il blocco degli script per le risorse locali di Internet Explorer

Se aprite una pagina html da un file di risorse locale del vostro disco (Es.: "C:\temp\miofile.htm") che contiene del codice javascript con Internet Explorer, vi appare un fastidiosissimo messaggio che dice: "Per facilitare la protezione, è stato impedito a questa pagina web di eseguire script o controlli ActiveXc potrebbero accedere al computer. Fare click qui per ulteriori opzioni...". A questo punto cosa fate? Fate click e selezionate "Consenti contenuto bloccato..". Tutto ok, peccato che la prossima volta che tornate su quella pagina dovete ripetere l'operazione.



Se siete uno sviluppatore web e usate la funzione di "Preview" con un software tipo Microsoft Expressions, potete capire come ciò dopo 2, 3 volte cominci ad essere insopportabile!
Dopo un po' di ricerche e tentativi ho trovato il flag che vi da una mano: Da menu "Opzioni internet" di Internet Explorer selezionate l'etichetta "Avanzate", scorrete fino alla sezione "Protezione" e spuntate il flag "Consenti l'esecuzione di contenuto attivo in file di Risorse del computer*" e premete OK. Adesso riavviate il browser e potete dire addio al messaggio.

Impedire l'esecuzione del programma .NET ad un utente che non sia amministratore

Un esigenza molto comune per esempio, se si vuole fare una console di amministazione di un servizio è quella che un applicazione o un metodo siano eseguiti solo se l'utente appartiene ad un determinato gruppo che ha i permessi necessari, per esempio ad accedere ad una determinata risorsa. Nel seguente esempio scritto in C# se l'utente che esegue il thread non è un amministratore allora il metodo genera un eccezione e si può chiudere l'applicazione.

Come prima cosa bisogna applicare i criteri principali del dominio applicazione corrente a WindowsPrincipal, altrimenti una richiesta di autorizzazione principale avrà esito negativo.
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
Ora abbiamo bisogno di sapere quale è l'utente che sta eseguendo il thread corrente.
//Estrae l'identità dell'utente del thread corrente
WindowsIdentity wi = (WindowsIdentity)System.Threading.Thread.CurrentPrincipal.Identity;
                
//Estrae il nome utente da suo sid
IdentityReference mYaccount = wi.User.Translate(typeof(NTAccount));
//Visualizza il nome utente estratto da suo sid
MessageBox.Show("Utente:" + mYaccount.Value);
Adesso dobbiamo ricavare il gruppo administrator da assegnare alla funzione di controllo. Per aiutarvi potete visualizzare i nomi dei gruppi a cui l'utente del thread appartiene così:
StringBuilder sbMsg = new StringBuilder();
foreach (IdentityReference sidRef in wi.Groups)
{
    IdentityReference account = sidRef.Translate(typeof(NTAccount));
    sbMsg.AppendLine(account.Value);
}
MessageBox.Show(sbMsg.ToString());
Ora per impedire all'applicazione di partire se non siamo amministratori, usiamo le seguenti istruzioni:
try
{
    PrincipalPermission permessi = 
        new PrincipalPermission(mYaccount.Value, "BUILTIN\\Administrators");
                
    permessi.Demand();
}
catch (SecurityException ex)
{
   MessageBox.Show(ex);
   //Esci dall'applicazione
}

Visualizzare il contenuto di una pagina html con javascript

Ecco un semplice script (utile anche per il debug) per visualizzare il contenuto di una pagina html con javascript:

<script type="text/javascript">
function viewSource()
{
    d=window.open();
    d.document.open('text/plain').write(document.documentElement.outerHTML);
}
</script>
All'interno di <BODY> aggiungete il seguente HTML:
<input type="button" value="View Source" onclick="viewSource()" />

Comprimere e decomprimere con .Net 2.0

Ecco come usare gli oggetti per la compressione messi a disposizione dal Framework .NET 2.0
//C#
using System.IO;
using System.IO.Compression;


public static class Compressor
{
 public static byte[] Compress(byte[] data)
 {
  MemoryStream output = new MemoryStream();
  GZipStream gzip = new GZipStream(output, CompressionMode.Compress, true);
  gzip.Write(data, 0, data.Length);
  gzip.Close();
  return output.ToArray();
 }


 public static byte[] Decompress(byte[] data)
 {
  MemoryStream input = new MemoryStream();
  input.Write(data, 0, data.Length);
  input.Position = 0;
  GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true);
  MemoryStream output = new MemoryStream();
  byte[] buff = new byte[64];
  int read = -1;
  read = gzip.Read(buff, 0, buff.Length);
  

  while (read > 0)
  {
   output.Write(buff, 0, read);
   read = gzip.Read(buff, 0, buff.Length);
  }
  

  gzip.Close();
  return output.ToArray();
 }
}
'VB
Imports System.IO
Imports System.IO.Compression


Public Class Compressor


 Public Shared Function Compress(ByVal data As Byte()) As Byte()
  Dim output As MemoryStream = New MemoryStream
  Dim gzip As GZipStream = New GZipStream(output, CompressionMode.Compress, True)
  gzip.Write(data, 0, data.Length)
  gzip.Close()
  Return output.ToArray
 End Function


 Public Shared Function Decompress(ByVal data As Byte()) As Byte()
  Dim input As MemoryStream = New MemoryStream
  input.Write(data, 0, data.Length)
  input.Position = 0
  Dim gzip As GZipStream = New GZipStream(input, CompressionMode.Decompress, True)
  Dim output As MemoryStream = New MemoryStream
  Dim buff(64) As Byte
  Dim read As Integer = -1
  read = gzip.Read(buff, 0, buff.Length)


  While read > 0
   output.Write(buff, 0, read)
   read = gzip.Read(buff, 0, buff.Length)
  End While


  gzip.Close()
  Return output.ToArray
 End Function


End Class

Icone dei componenti nella Toolbox .NET

Per aggiungere un icona ad un nuovo componente creato con Visual Studio in modo che si veda nella toolbox si può usare uno dei seguenti metodi:
//C#
//Specifica la bitmap associata al tipo Button.
[ToolboxBitmap(typeof(Button))]
class MyControl1 : UserControl
{
}


//Specifica un bitmap file.
[ToolboxBitmap(@"C:\Documents and Settings\Rudy\Documenti\Immagini\myImage.bmp")]
class MyControl2 : UserControl
{
}


//Specifica un tipo che indica l'assembly in cui cercare e il nome del immagine nelle risorse.
[ToolboxBitmap(typeof(MyControl), "MioControlloBitmap")]
class MyControl : UserControl
{
}
'VB
'Specifica la bitmap associata al tipo Button.
 _
Class MyControl1
    Inherits UserControl
End Class


'Specifica un bitmap file.
 _
Class MyControl2
    Inherits UserControl
End Class


'Specifica un tipo che indica l'assembly in cui cercare e il nome del immagine nelle risorse.
 _
Class MyControl
    Inherits UserControl
End Class
Va ricordato che l'immagine deve essere una bitmap a 16x16 o 32x32, inoltre se usate il primo metodo l'immagine nelle risorse deve chiamarsi "Namespace.NomeClasse.bmp" mentre se usate l'ultimo "Namespace.MioControlloBitmap"

Percorso del file eseguibile di un programma .NET

Per ottenere il percorso del file eseguibile da cui è partita l'applicazione, il namespace System.Windows.Forms ci mette a disposizione il metodo statico Application.StartupPath.
Tuttavia se non vogliamo o non possiamo referenziare System.Windows.Forms, ad esempio, per ottenere il percorso in funzione di una dll referenziata nel progetto, allora possiamo usare il seguente metodo:
AppDomain.CurrentDomain.SetupInformation.ApplicationBase
Prestate molta attenzione se volete aprire un file che si trova nella stessa cartella dell'eseguibile, è buona norma che passiate al metodo il percorso e il nome del file Es.: File.Open(@"C:\Progetti\MiaApplicazione\test.txt"). Se usate solamente il nome file Es.: File.Open(@"test.txt") e per caso in precedenza avete usato una OpenFileDialog o SaveFileDialog per aprire o salvare un file il percorso in cui verrà cercato il vostro file text.txt sarà equivalente all'ultimo selezionato tramite questi controlli.

P.S: anche System.Environment.CurrentDirectory soffre dello stesso problema.

Filtrare i tipi di files di HTML file input

Con le specifiche HTML 4.01 è stato definito un attributo chiamato accept per i tag di tipo input type="file".

Questo attributo è usato per specificare un lista di contenuti (MIME types) separata da virgola che il server può processare correttamente quando gli viene inviato il form (che contiene il tag input). Ad esempio se si vuole indicare che i tipi validi da passare al server sono solo immagini gif o jpeg aggiungiamo l'attributo accept="image/gif,image/jpeg" al tag input.

E'supportato anche l'uso delle wildcards, ciò significa che per indicare ad esempio tutti i files di tipo immagine posso scrivere "image/*" (anche se questa sintassi non esprime un tipo MIME valido) .

I browsers posso usare questa informazione per filtrare i tipi di files accettati. Sfortunatamente sembra che il supporto attuale dei browsers sia inesistente, nessun filtro viene applicato anche se specificato .

L'unico modo per dare un po' di conforto agli utenti è usare javascript lato client. Ad esempio, se volessimo fare si che un utente debba specificare per forza un file di tipo JPEG potremmo scrivere:

<SCRIPT language=JavaScript type=text/javascript><!--
function Controlla(testoVuoto)
{
 var ext = document.frm.immagine.value;
 if(ext.length != 0)
 {
  ext = ext.substring(ext.length-3,ext.length);
  ext = ext.toLowerCase();
  if(ext != 'jpg')
  {
   alert('Hai selezionato un file .'+ ext +
   ' ma sono accettati solo i file .jpg!');
   return false;
  }
 }
 else if(testoVuoto)
 {
  alert('Seleziona un file .jpg!');
  return false;
 }

 return true;
}
//--></SCRIPT>
<FORM name=frm onsubmit="return Controlla(true);" 
action=http://www.visual-basic.it/Upload.aspx method=post encType=multipart/form-data>
<P>Seleziona un file JPEG (.jpg) da caricare:</P>
<BR>
<INPUT type=file accept=image/jpeg size=50 name=immagine>
<P>Includi anche una breve descrizione:</P>
<BR>
<TEXTAREA onfocus=Controlla(false); name=txtDesc rows=3 cols=40></TEXTAREA>
<INPUT type=submit value=Manda>
</FORM>

Lettura e scrittura con MemoryStream .NET

Poichè ogni volta che devo usare un MemoryStream devo sempre ricordarmi come funzionano gli stream e le operazioni di lettura e scrittura meglio postare questo pezzetto di codice che può essere utile:
//C#
System.IO.MemoryStream ms = new System.IO.MemoryStream();
Byte[] by = System.Text.Encoding.UTF8.GetBytes("Mio testo");
ms.Write(by, 0, by.Length);
ms.Position = 0;
Byte[] buffer = new byte[by.Length];
ms.Read(buffer, 0, buffer.Length);
string sTesto = System.Text.Encoding.UTF8.GetString(buffer);
'VB
Dim ms As System.IO.MemoryStream = New System.IO.MemoryStream
Dim by As Byte() = System.Text.Encoding.UTF8.GetBytes("Mio testo")
ms.Write(by, 0, by.Length)
ms.Position = 0
Dim buffer(by.Length) As Byte
ms.Read(buffer, 0, buffer.Length)
Dim sTesto As String = System.Text.Encoding.UTF8.GetString(buffer)

Singola istanza di un applicazione C#

Per essere sicuri si eseguire una singola istanza di un applicazione C# potete scrivere il seguente codice:
//C#
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;

namespace ProvaCSharp
{
 static class Program
 {
  private static Mutex mutex;

  ///
  /// The main entry point for the application.
  /// 
  [STAThread]
  static void Main()
  {
   mutex = new Mutex( true, Application.ProductName );
   if (mutex.WaitOne(0, false))
   {
    Application.Run(new Form1());
   }
   else
   {
    MessageBox.Show(Application.ProductName + " è già in esecuzione");
   }
  }
 }
}

Modificare lo stato di un controllo da un operazione asincrona .NET

Quante volte avete avuto la necessità di aggiornare un controllo che si trova su una form istanziata dal thread principale dell'applicazione, da un altro thread che sta seguendo un operazione asincrona? Ecco come evitare errori di cross thread e non duplicare il codice:
//C#
private delegate void InvokeMiaFunzione();
private InvokeMiaFunzione mInvokeMiaFunzione;

private void MiaFunzione()
{
 if (this.InvokeRequired)
 {
  this.Invoke(mInvokeMiaFunzione);
 }
 else
 {
  // Qui si può modificare lo stato del controllo della form senza incorrere in nessun problema
 }
}

private void CostruttoreDellaClasse()
{
 mInvokeMiaFunzione = new InvokeMiaFunzione(MiaFunzione);
}

//Chiamata da un processo asincrono
private void ProcessoAsincrono()
{
 MiaFunzione();
}

//Chiamata da un processo sincrono
private void ProcessoSincrono()
{
 MiaFunzione();
}
'VB
Private Delegate Sub InvokeMiaFunzione()
Private mInvokeMiaFunzione As InvokeMiaFunzione

Private Sub MiaFunzione()
    If Me.InvokeRequired Then
        Me.Invoke(mInvokeMiaFunzione)
    Else
        'Qui si può modificare lo stato del controllo della form senza incorrere in nessun problema
    End If
End Sub

Private Sub CostruttoreDellaClasse()
    mInvokeMiaFunzione = AddressOf MiaFunzione
End Sub

'Chiamata da un processo asincrono
Private Sub ProcessoAsincrono()
    MiaFunzione()
End Sub

'Chiamata da un processo sincrono
Private Sub ProcessoSincrono()
    MiaFunzione()
End Sub

I files di configurazione di un applicazione .NET

Segnalo questo link, al mio primo articolo, relativo ai files di configurazione delle applicazioni .NET, è stato scritto qualche anno fa, ma a oggi è ancora valido.

giovedì 1 dicembre 2011

PyQt maemo: Scrollare del testo

qte = QtGui.QTextEdit()
scroller = qte.property("kineticScroller").toPyObject()
scroller.setEnabled(True)

Le basi di PyMaemo – terza parte

Questo articolo che segue è la traduzione italia, rivisitata dell'articolo "Python for Newbies – Tutorial" http://www.themaemo.com/python-for-newbies/.

Il contenuto del tutorial è fornito sotto la licenza "Creative Commons Attribution-Share Alike 3.0":
http://creativecommons.org/licenses/by-sa/3.0/ http://creativecommons.org/licenses/by-sa/3.0/legalcode

Contenuto di questo post:

Numeri

Notate che nell'ultimo esempio il numero ritornato da Python è un numero con il punto dopo il decimale. In termini informatici questo è chiamato numero a virgola mobile. Dato che l'esperssione include un numero a virgola mobile (3.0), il suo valore è automaticamente convertito il numero a virgola mobile. La ragione della differenziazione per i tipi di numeri non è scopo di questo tutorial. Nella maggior parte dei linguaggi di programmazione si deve stare attenti a usare il giusto tipo di numero per ogni applicazione. In Python è bene sapere che ci sono diversi tipi di numeri, ma di solito è Python che si occupa dei vari dettagli. L'unica cosa di cui bisogna stare attenti è la divisione. Guardate:
>>> 7 / 2
3
Dal momento che entrambi i numeri della divisione sono interi (un tipo di numero senza decimali) Python esegue una divisione intera. Questo può non è ciò che si aspetta qualcuno ha esperienza di programmazione. Attualmente, per ovviare a questo si può fare così:
>>> 7.0 / 2     # or float(7) / 2
3.5
Nelle versioni più recenti di Python (version 3.x), i progettisti hanno deciso di cambiare questo comportamento in modo che i nuovi utilizzatori di Python ottengano quello che si aspettano. Con la versione corrente di Python di Maemo 5 si può già utilizzare questa funzionalità importando il modulo "__future__". Parleremo più avanti di 'importazione'.

Alcuni operatori comuni associati ai numeri sono i seguenti:

Descrizione operatori

+ Addizione
- Sottrazione
* Moltiplicazione
/ Divisione
% Resto (e.g. 9%2=1; 8%2=0)
** Potenza (4**2=16)

Ci sono anche molte funzioni matematiche in Python per fare praticamente qualsiasi operazione necessaria. Ecco un piccolo esempio (si veda la documentazione per ulteriori). Per utilizzarli devi prima importarli dal modulo per la matematica, come questo ad esempio:
from math import acos
Descrizione funzioni

acos(x) Ritorna l'arcoseno di x
cos(x) Ritorna il coseno di x
log(x) Ritorna l'algoritmo naturale di x
sqrt(x) Ritorna la radice di x
tanh(x) Ritorna la tangente iperbolica di x

Un consiglio pratico è che nel prompt dei comandi interattivo è possibile richiamare l'ultima espressione stampata con il carattere di sottolineatura "_". Così, per esempio, è possibile utilizzare Python come una calcolatrice a portata di mano:
>>> 2 + 2
4
>>> _ + 6
10
C'è anche una estensione Python speciale chiamato Numerical Python (NumPy) che gli permette di utilizzare le funzioni matematiche superiori, come l'algebra lineare e matrici. Ma, basta con i numeri per ora.

Stringhe

Abbiamo già visto una stringa nel esempio "Hello World" di prima. "Una stringa è un insieme ordinato di caratteri, utilizzati per immagazzinare e rappresentare il testo-base di informazioni". Le stringhe Python possono essere racchiuse in doppia, singola, o addirittura tripla (per le linee multi-stringa) virgoletta. Ad esempio:
>>> 'Hello World'
'Hello World'
>>> "Hello 'Hello World'"
"Hello 'Hello World'"
>>> '''This is a longer string that spans
… several lines, doesn’t say anything
… meaningful, and ends here'''
Il fatto che le stringhe sono "ordinate" significa che siamo in grado di accedere ai propri componenti in base alla posizione. Ogni carattere in una stringa ha una posizione di indice dinanzi ad esso. Ad esempio la stringa "Python", ha gli indici seguenti:

Indici stringa
0 1 2   -2  -1
 P y  t h  o   n
Si noti che il primo carattere "P" nei linguaggi di programmazione tipo il C è situato a indice 0, invece è a 1 ad esempio nel basic. Tuttavia, a differenza del C, con Python è anche possibile utilizzare gli indici negativi, che iniziano a decorrere dalla fine della stringa.

Per ottenere i caratteri situati a determinati indici possiamo utilizzare il loro indice numerico scrivendolo all'interno delle parentesi. Diamo un'occhiata ad alcuni esempi.

Per ottenere il carattere situato all'inizio della stringa possiamo usare:
>>> "Python"[0]
'P'
Se stiamo usando una variabile:
>>> hw = "Hello World"
>>> hw[0]
'H'
>>> hw[1]
'e'
>>> hw[-1]
'd'
Possiamo anche ottenere "parti" di una stringa specificando il primo e l'ultimo indice della fetta separati da due punti.
>>> hw[1:7]
'ello W'
>>> hw[4:-2]
‘o Wor’
Il limite a destro o a sinistro della stringa può essere specificato anche, lasciando vuoto l'indice. Ad esempio:
>>> hw[:5]
'Hello'
>>> hw[6:]
'World'
>>> hw[:]
'Hello World'
Le stringhe "oggetti" molto intelligenti. Sanno come comportarsi correttamente in molte situazioni come ad esempio:
Quando aggiungiamo una stringa alla stringa
>>> hw + " Today"
'Hello World Today'
>>> hw[:5] + " You"
'Hello You'
Multiplication
>>> hw[:6] * 5
'Hello Hello Hello Hello Hello '
Si noti che in tutte le operazioni che abbiamo fatto finora con le stringhe, l'operazione restituisce un risultato, ma la stringa originale rimane sempre invariata. È così che le stringhe funzionano. Una stringa è quella che viene chiamata una sequenza di "immutabile". Ciò significa che per modificare una stringa in realtà dobbiamo creare una nuova stringa. Ad esempio:

Provando a cambiare il valore della stringa in un determinato punto
>>> hw[0] = "M"
Viene generato un errore!

Tuttavia, le variabili sono così flessibili che possiamo semplicemente assegnare un nuovo valore ad esso:
>>> hw= "M" + hw[1:]
>>> hw
'Mello World'
Questo funziona perchè l'espressione hw[1:] è calcolata per prima e poi "M" viene aggiunto ad essa, e infine il risultato è assegnato al valore della variabile hw.

Un altro modo per unire le stringhe con le variabili è la formattazione delle stringhe. Ad esempio, cosa succederebbe se si avesse un programma che accoglie l'utente in base al nome a seconda dell'ora del giorno. Per esempio, si potrebbe dire qualcosa del tipo: "Ciao Joe. Come stai sta mattina? ". In questo caso il programma potrebbe raccogliere il nome dell'utente in qualche modo e inserirlo in una variabile denominata "name". Si potrebbe anche prendere il momento della giornata guardando l'orologio computer, determinare se è mattina, pomeriggio o sera, e mettere il risultato in una variabile denominata "time_of_day". Con la seguente riga nel vostro programma possiamo fondere le variabili in una stringa:
>>> Saluto = "Ciao %s. Come stai questa %s" % (name, time_of_day)
Python sostituisce le occorrenze %s con la rispettiva variabile nella tupla dopo il carattere %. (Una "tupla" è una sequenza di elementi all'interno di una parentesi. Le tuple verranno spiegate più avanti.) Ecco un altro esempio:
>>> dessert = "Pecan Pie"
>>> max_per_person = 1
>>> answer = "The dessert of the day is %s. You can only take %i per person" % (dessert, max_per_person)
>>> answer
"The dessert of the day is Pecan Pie. You can only take 1 per person"
In questo esempio abbiamo aggiunto una variabile stringa e una variabile intero nella stringa di risposta. Stringhe e interi hanno differenti codici di formattazione (%s,%i). Guardare la documentazione di Python per gli altri codici di formattazione.

Stringhe inoltre sono dotati di alcuni metodi come i seguenti:
>>> "hello".capitalize()
'Hello'
>>> "HELLO".lower()
'hello'
>>> 'hello'.upper()
'HELLO'
>>> 'Hello World'.replace(" ", "-")     #Replace occurrences of first parameter with second
'Hello-World'
>>> ' Hello World '.lstrip()     #To strip the whitespace at the left of string
'Hello World '
>>> ' Hello World '.rstrip()     #To strip the whitespace at the right of string
' Hello World'
>>> ' Hello World '.strip()     #To strip the whitespace at the left and right
'Hello World'
>>> "This is a longer string".split()
['This', 'is', 'a', 'longer', 'string']
Nell'ultimo esempio vediamo come il metodo Split restituisce una lista di stringhe. La stringa originale è separata in parti delimitate dal delimitatore fornito. Quando non è fornito nessun delimitatore, di default è utilizzato lo spazio bianco. Ma, che cosa è una lista? Lo vedremo in seguito!

Le basi di PyMaemo – seconda parte

Questo articolo che segue è la traduzione italia, rivisitata dell'articolo "Python for Newbies – Tutorial" http://www.themaemo.com/python-for-newbies/.

Il contenuto del tutorial è fornito sotto la licenza "Creative Commons Attribution-Share Alike 3.0":
http://creativecommons.org/licenses/by-sa/3.0/ http://creativecommons.org/licenses/by-sa/3.0/legalcode

Contenuto di questo post:
Elementi costitutivi di un programma Python

Prima di tutto, cosa è un programma?  Un programma è una sequenza di istruzioni specifiche per eseguire un calcolo. Entriamo in modalità interattiva (Sul dispositivo N900, lanciate l'applicazione X-Terminal e immettete il seguente comando: "Python"), e facciamo il nostro primo programma tradizionale:
>>> print "Hello World" 
Hello World 
La parola "print" è un comando proprietario o "dichiarazione" che visualizza l'argomento passato sullo schermo. Al seconda parte del programma che segue la dichiarazione print è l'argomento stesso, in questo caso  la stringa “Hello World”. Le virgolette servono per trattare la parola dentro di esse come una stringa invece di un comando o una variabile. (Una "string" è una sequenza di caratteri che compongono una parola, una frase, ecc.. Vedremo più avanti ulteriori dettagli.)

Nota:
Tipicamente, nei manuali e tutorials Python, quando viene mostrato del codice in una sessione interattiva, la riga di comando attiva inizia con ">>>" Quando invece iniziamo a scrivere una serie di istruzioni (su più righe), la riga di comando attiva inizia con "..."

Nota:
Il testo scritto dopo # è un commento e viene ignorato dall'interprete di Python.

Variabili

Cosa è una variabile? Una variabile è un nome (o una parola) che si riferisce ad un certo valore. Noi possiamo usare quasi ogni parola ed assegnarle un valore. Ad esempio:
>>> hi = "Hello World"
La parola "hi" è adesso il nome della variabile che contiene la stringa "Hello World". Proviamo ad usare l'istruzione "print" per visualizzare il valore di "hi":
>>> print hi 
Hello World
In Python le variabili sono veramente flessibili. Non serve dichiararle prima come negli altri linguaggi. Si può assegnare ad esse un valore anche se ne hanno già uno di tipo diverso. Per esempio andiamo a cambiare il valore di "hi" in 3.0:
>>> hi = 3.0 
>>> print hi 
3.0
Possiamo anche assegnare una variabile come valore di un altra. Per esempio:
>>> num = hi 
>>> print num 
3.0
Un'altra caratteristica della shell di Python è che è che non c'è bisogno di utilizzare l'istruzione "print" per visualizzare il valore di una variabile. Si può semplicemente digitare il nome e Python lo visualizzerà.
>>> num 
3.0
Espressioni

Alla linea di comando interattiva si possono digitare espressioni e vedere il loro risultato. Un espressione è una combinazione di variabili, operatori e valori che rappresentano un singolo valore risultante. Ad esempio:
>>> num + 2 
5.0 
>>> ((5 – 1) + num) * 2 
14.0
Possiamo assegnare un valore ad un espressione. Come ad esempio:
>>> numb = ((5 – 1) + num) * 2 
>>> numb 
14.0

Le basi di PyMaemo – prima parte

Questo articolo che segue è la traduzione italia, rivisitata dell'articolo "Python for Newbies – Tutorial" http://www.themaemo.com/python-for-newbies/.
Il contenuto del tutorial è fornito sotto la licenza "Creative Commons Attribution-Share Alike 3.0":
http://creativecommons.org/licenses/by-sa/3.0/
http://creativecommons.org/licenses/by-sa/3.0/legalcode
Il questo tutorial si toccheranno molte aree del linguaggio Python in particolare nel contesto del sistema operativo Maemo e in maniera veramente semplice, alla portata di tutti.
La versione delle librerie di Python trattate è la 2.5.4, che è quella attualmente disponibile per il dispositivo N900.
Il tutorial originale è diviso in due parti, io invece lo diveiderò ancora di più postando un pò di cose al giorno:
Contenuto di questo post:
Cosa è Python?
Python un linguaggio di programmazione creato inizialmente da Guido Van Rossum, che lo rilasciò come programma "Open Source" "Free".

Da allora è stato progressivamente migliorato con il contributo di centinaia di programmatori di computer in tutto il mondo. Il pacchetto Python può essere scaricato gratuitamente da internet per tutte le principali piattaforme informatiche esistenti. Può essere utilizzato e modificato, anche per quasi qualsiasi scopo.
Perché Python?
Esistono molti linguaggi di programmazione. Tutti hanno differenti vantaggi e svantaggi. Il cervello di un computer è il suo processore, ed esso non capisce l'inglese. Il processore ha bisogno di ricevere l'input in un formato che arriva a capire. La maggior parte dei processori sono fatti per capire i comandi formattati come una serie di zeri "0" e uni "1".

Questo formato è chiamato binario. Sebbene sia possibile scrivere programmi a mano dei programmi con questo formato di zeri e uni, è sconsigliato e molto difficile, anche perché richiede molto tempo, ed è soggetto a errori. Questo è il motivo per cui sono stati inventati i linguaggi di programmazione.
I linguaggi di programmazione sono spesso classificati come "basso livello" o "alto livello".
I linguaggi a basso livello sono stati i primi a comparire ed hanno semplificato il processo di scrittura delle istruzioni per il computer, mediante l'utilizzo di parole comprensibili. Un programma traduttore, "compilatore", traduce le istruzioni del programma in un file binario che è comprensibile dal processore.

Tuttavia, i linguaggi di programmazione a basso livello sono ancora piuttosto difficile da padroneggiare. Essi costringono il programmatore a comprendere il modo in cui il computer funziona internamente. Il programmatore deve dare le istruzioni per ogni passo che il computer deve adottare per gestire un determinato compito, che può facilmente portare ad errori e gravi problemi. D'altra parte, i programmi di basso livello tendono ad essere abbastanza veloci ed efficienti (se scritti correttamente).
Linguaggi di alto livello sono stati progettati per rendere più facile programmare. Le istruzioni sono più simili al linguaggio normale, e molti dettagli sono gestiti dal compilatore. Questo rende i tempi di sviluppo molto più brevi, a discapito della velocità, rispetto ad un programma di basso livello.
Python è un linguaggio di programmazione ad alto livello. Molti lo considerano il linguaggio di programmazione più semplice da imparare e da programmare. Molti compiti, che normalmente dovrebbe svolgere il programmatore, sono già integrati nel linguaggio.

Python è molto utile ed è semplice e veloce per scrivere qualsiasi programma, da un semplice script a programmi per sistemi client/server. Questo è vero soprattutto con i computer di oggi che sono ultra veloci e compensano lo svantaggio della velocità intrinseca dei linguaggi di programmazione ad alto livello. Ai programmatori Python piace per la sua sintassi chiara e logica, che riduce enormemente i cicli di sviluppo.

Questo linguaggio costringe i programmatori ad utilizzare l'indentazione del codice, in modo corretto. All'inizio può sembrare scomodo, ma dopo essersi adeguati, si notano i vantaggi di un codice molto pulito e manutenibile (anche se il codice è stato scritto da qualcun altro).
Installare Python
Per installare Python sul dispositivo N900, basta installare in applicazione che lo usa. Ad esempio "pyGTKeditor". Se stai usando Linux Python è già installato. In windows devi andare su www.python.org/download/ e scaricare Python 2.6.4, non l'ultima versione 3.x, perché non è pienamente compatibile con quella del N900. (Non è molto diversa ma basta per non fare funzionare le cose)
Come funziona Python
I programmi Python sono eseguiti con l'aiuto di un "interprete". L'interprete è un programma che converte il codice in istruzioni binarie necessarie al processore, in fase di esecuzione. C'è un interprete diverso, per ogni piattaforma dove Python viene eseguito.

Questo consente al codice Python scritto in una macchina Windows, di funzionare senza variazioni, in una macchina Linux, Macintosh, o anche in uno smart phone. Naturalmente, ci sono anche molte caratteristiche specifiche per ogni piattaforma, che sono ottimizzate per essa (Evitare di usare queste se non si vuole legare il programma alla piattaforma specifica.).

L'interprete deve essere installato sul computer che eseguirà il programma Python, oppure confezionato assieme al programma stesso, in modo che possa essere eseguito dal computer senza bisogno di Python.
L'interprete può essere eseguito direttamente da quella che viene chiamata "riga di comando interattiva". I comandi Python possono essere digitati direttamente in questa sessione e vengono trattati immediatamente mostrando i risultati ottenuti. Questa caratteristica unica consente di eseguire dei test rapidi di idee e pezzi di codice.
La maggior parte dei programmi, tuttavia, sono scritte con editor di testo e salvati estensione ".py", e eseguiti come processo indipendente. Poiché non vi è alcuna necessità di "elaborare" un programma Python prima di eseguirlo, un programmatore può verificare le, modifiche al codice immediatamente dopo il loro salvataggio.

Sviluppo PyMaemo da N900 con PyGTKEditor

Un altra alternative che vi propongo è lo sviluppo diretto sul dispositivo. Questo è possibile installando PyGTKEditor http://maemo.org/downloads/product/Maemo5/pygtkeditor/ Questo bel programmino ci consente di sviluppare in Python (e molti altri linguaggi), fornendoci varie utilità tipo la colorazione del testo in base sintassi del linguaggio di programmazione.

Inoltre possiamo salvare ed eseguire lo script direttamante dal programma, aggiungere o rimuovere commenti, identare il codice manualmente o in automatico, cercare e/o sostituire testi nel codice, ecc.. come in un normale IDE desktop.

Ecco alcune scorciatoie da tastiera disponibili:
  • Ctrl-O : Apre il file
  • Ctrl-S : Salva file
  • Ctrl-W : Chiude file
  • Ctrl-I : Mostra informazioni sul file
  • Ctrl-Z : Annulla modifica
  • Ctrl-Y : Ripristina modifica
  • Ctrl-D : Duplica una linea di codice
  • Ctrl-F : Trova
  • Ctrl-R : Sostituisci
  • Ctrl-A : Seleziona tutto
  • Ctrl-E : Esegui
  • Ctrl-H : Visualizza l'help

Sviluppo PyMaemo da PC con PluThon

Per un ambiente di sviluppo completo potete provare “PluThon 2nd Edition (Final)” http://pluthon.garage.maemo.org/2nd_edition/, col quale possiamo sviluppare e debuggare le applicazioni direttamente sul dispositivo.

Cominciamo l’installazione:

Per prima cosa installiamo sul nostro PC “Cygwin” http://www.cygwin.com/ per windows (scaricare e installare "setup.exe").

Dopo di che scarichiamo ed installiamo: “PC-Connectivity_0.9.4.exe” https://garage.maemo.org/projects/pc-connectivity che ci permetterà di creare una rete tramite cavo USB fra PC e dispositivo N900.

Sul dispositivo N900 abilitiamo il repository extras-devel e installiamo “maemo-pc-connectivity”, un programma per poter creare delle reti ad-hoc fra cui quella USB. Durante l'installazione, ci verrà chiesto di impostare una password, che sarà quella dell'utente “user”.

Installiamo sul PC “Python 2.5” http://www.python.org/download/releases/2.5.4/

Adesso possiamo procedere all'installazione di “PluThon” http://pluthon.garage.maemo.org/2nd_edition/installation_product.html: Scarichiamo “Final Common Components” e “Final Win32 Support” e estraiamo i contenuti in una stessa cartella.

Adesso possiamo avviarle l'ambiente di sviluppo, eseguendo il file “pluthon.exe”.

Creiamo un nuovo progetto: Dal menu del programma, “File” > “New” > “Pluton project”, selezioniamo il template da utilizzare e premiamo il bottone “Next”. Ora ci vengono proposte 4 modalità di connessione al dispositivo remoto:

Maemo device (USB) (192.168.2.15)
Maemo device (Bluetooth) (192.168.3.15)
Maemo device (WLAN ad-hoc) (192.168.4.15)
Maemo device (user-configured) (PLEASE-CONFIGURE-ME.LOCAL)

Selezioniamo la modalità USB.
Prima di proseguire dobbiamo configurare il dispositivo N900.
Dal menu di “Impostazioni” avviamo “PC-Connectivity manager”, e premiamo il bottone “Advanced”.

Alla voce “Environments” clicchiamo i tre puntini “...”  e poi il bottone “New”. Diamo un nome significativo alla nuova connessione. Es.: “USB devel”. Selezioniamo l'elemento appena creato sulla lista e premiamo il bottone “Select”.

Premiamo il bottone “Basic”, spuntiamo la casella “USB” e premiamo il bottone “Apply”.

In “Connection type” selezioniamo USB, e come opzioni scegliamo “PC Suite”.
Premiamo il bottone “Apply” e poi “Save”.
Ora,  e avviamo una nuova connessione ad internet e dal menu “Seleziona una connessione” selezionando “devel_adhoc”

Colleghiamo il cavo USB fra il PC e il dispositivo (se è tutto ok parte l'installazione di un driver sul PC).
Sul dispositivo N900 selezioniamo “Modalità PC Suite”.
Sul PC avviamo il programma “USB Networking”, selezioniamo “Static IP” e premiamo il bottone “Apply”

Per verificare se è tutto ok facciamo un ping all'indirizzo 192.168.2.15

Ora possiamo continuare col nuovo progetto Pluthon, ci verrò chiesto di controllare i packages necessari per il progetto, premiamo “Yes”.
Premiamo “Finish” e dopo un po'ci viene chiesto di creare una connessione SSH, premiamo “Yes”.

Ci verrà richiesta la password per l'utente “user”, che abbiamo impostato in precedenza sul dispositivo N900 (installazione di “maemo-pc-connectivity”), scriviamo la password e se vogliamo spuntiamo la casella "Save password" in modo che non venga richiesta ogni volta.

Ora ci viene richiesto di installare sul dispositivo i cataloghi “extras-devel” e “extra-tools” e successivamente la password dell'utente “root”, che se non l'avete cambiata è “rootme” di default.

Adesso siete pronti per iniziare a sviluppare.

Scrivetemi pure per domande o eventuali approfondimenti.