·
Web del proyecto http://gmendezm.blogspot.com/2013/03/gupdrive.html
·
Descarga de
gUpDrive: Enlace
de descarga (Comprimido en zip)
·
Tutorial/Manual
de cómo usarlo
·
Aplicación,
Detalles Básicos
o Nombre: gUpDrive
o Versión: 1.0
o Licencia: Libre, Gratuita, Código Cerrado (Por el momento).
o Objetivo
Principal: Subir imágenes fácilmente
a Google Drive de manera eficiente.
o Objetivos Secundarios
§
Subir archivos
desde el portapapeles
§
Subir archivos
desde el disco duro usando el evento Drag & Drop
·
Desarrollo
·
Licencia
A continuación se muestran una serie de
características del programa.
|
El portapapeles o
Clipboard, es un espacio de la memoria del computador que la plataforma (es
decir el sistema operativo) almacena todo tipo de datos.
Algunos tipos datos son:
1. Texto
2. Archivos
3. Imágenes
4. Contenido Multimedia
|
gUpDrive revisa el portapapeles
y verifica si hay un formato de imagen que pueda ser subido.
Algunos formatos son:
1. JPG
2. JPEG
3. PNG
4. GIF
5. BMP
Los más livianos suelen
ser los GIF destinados a las animaciones con baja capacidad de colores.
Luego están los archivos
JPG y JPEG, y los más pesados suelen ser los PNG y BMP.
gUpDrive permite subir cualquiera de estos 4 tipos de archivos.
En caso de que el
portapapeles no contenga imágenes, no se subirá ningún archivo.
|
Tanto los programas como
los sistemas operativos tienen eventos. gUpDrive comparte eventos entre la
aplicación y el sistema operativo. Al arrastrar archivos desde el sistema
operativo, el programa los recibe como parámetros y parsea cada ruta de los
archivos, filtrándolos de manera que solamente las imágenes son agregadas.
Este evento se conoce como Arastra y Suelta, o Drag and Drop. Otros eventos
son Click, MouseDown, MouseUp, Hover, MouseWheel, Focus, entre otros.
|
Con este sistema se pueden
agregar varios archivos que se arreglan a una cola de archivos que van siendo
subidos uno a uno, de manera asíncrona. Es decir, el programa puede ser
utilizado mientras las imágenes están siendo subidas.
Cada vez que se termina de
subir un archivo este se agrega a la lista. Esta lista permite seleccionar los
elementos subidos de dos formas:
1. Selección Simple: Seleccionar un elemento
2. Selección Múltiple: Seleccionar varios elementos,
incluso seleccionarlos todos
Cuando se cierra la
aplicación, la lista se guarda en un archivo. Cuando se vuelve a abrir la
aplicación, el programa carga desde el archivo la lista, así que el usuario no
pierde sus datos al cerrar la aplicación, a menos que borre dichos archivos. En
caso de que dichos archivos se borren por accidente, el programa sigue
funcionando.
Modificar los archivos
manualmente puede provocar errores en el funcionamiento del programa.
En la lista al dar click
derecho en un elemento, se despliega la opción compartir, con la cual se puede
enviar una petición a la red social para publicar la imagen.
Las redes sociales permitidas
son las siguientes:
·
Facebook
·
Twitter
·
Google+
·
Tumblr
·
Delicious
Facebook
Twitter
Google+
Tumblr
Delicious
La interfaz gráfica de
esta aplicación está compuesta por los siguientes controles gráficos:
1. Botones: Los botones son los utilizados para subir los
archivos a tarvés del portapapeles y el evento Drag&Drop
2. Listas: Se utiliza una lista para enlistar los
archivos subidos
3. Áreas de Texto: Se usa una caja de texto para
almacenar los enlaces con formato específico
4. Menú Desplegables: Hay dos menú desplegables, el
primero es al dar click sobre la lista, que tiene las opciones de eliminar y
compartir, mientras que el otro menú se desplega al dar click en ciertas áreas
en blanco de la ventana, que tiene las opciones de salir y cambiar el skin.
5. Controladores Checkbox: Permite configurar con valores
booleanas, el funcionamiento de los algoritmos que muestran los enlaces
formateados y también las acciones a realizar una vez terminado de subir un
archivo.
6. Etiquetas: Muestran ayuda visual para la comprensión
del programa, además permiten incluir imágenes para mejorar el aspecto visual.
7. Ventanas: Todo el programa funciona sobre una única
ventana, que muestra la aplicación, como información sobre el desarrollador.
La información a
continuación no está relacionada con el funcionamiento del proyecto sino con
detalles técnicos que pueden interesar a otros programadores y desarrolladores
de aplicaciones.
El proyecto fue
desarrollado en Netbeans:
Se utilizaron opciones
para verificar el correcto funcionamiento del programa usando la clase
Exception y todas aquellas cuya jerarquía pertenece a esta superclase. Por
ejemplo IOException.
El siguiente algoritmo
permite verificar que solo se puedan subir archivos de imágenes al arrastrar
ArrayList<String> extensionesAdmitidas = new
ArrayList<String>();
Collections.addAll(extensionesAdmitidas,
"jpg", "png", "gif", "bmp", "jpeg");
for (int i = 0; i < files.length;
i++) {
try {
if (!uploader.rutas.contains(files[i].getCanonicalPath()))
{
if
(extensionesAdmitidas.contains(getExtension(files[i].getCanonicalPath()))) {
uploader.rutas.add(files[i].getCanonicalPath());
}
}
} catch (IOException
ex) {
Logger.getLogger(v0.class.getName()).log(Level.SEVERE,
null, ex);
}
}
Se utilizaron
características propias de conexión y servicios, como lo son los objetos Json y
los métodos Callback:
public void conectar() throws
GeneralSecurityException, IOException, URISyntaxException {
HttpTransport httpTransport = new
NetHttpTransport();
JacksonFactory jsonFactory = new
JacksonFactory();
GoogleCredential credential = new
GoogleCredential.Builder().setTransport(httpTransport).setClientSecrets(CLIENT_ID,
CLIENT_SECRET).setJsonFactory(jsonFactory).setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(DriveScopes.DRIVE_FILE)
//.setServiceAccountUser(userEmail)
.setServiceAccountPrivateKeyFromP12File(new
java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH)).build();
service = new
Drive.Builder(httpTransport, jsonFactory, null).setHttpRequestInitializer(credential).build();
}
Para poder trabajar con el
API de Google se hizo uso de las credenciales.
Las librerías que utilicé
fueron las siguientes:
Librería
|
Peso
|
AbsoluteLayout.jar
|
2.8 kB
|
commons-net-3.2.jar
|
269 kB
|
DocumentListDemo.jar
|
26.5 kB
|
filedrop.jar
|
25.0 kB
|
gdata-docs-3.0.jar
|
118 kB
|
gdata-docs-meta-3.0.jar
|
4.4 kB
|
google-api-client-1.10.3-beta.jar
|
113 kB
|
google-api-client-appengine-1.10.3-beta.jar
|
3.2 kB
|
google-api-client-servlet-1.10.3-beta.jar
|
10.1 kB
|
google-api-services-drive-v2-rev5-1.7.2-beta-javadoc.jar
|
4.2 MB
|
google-api-services-drive-v2-rev5-1.7.2-beta-sources.jar
|
335 kB
|
google-api-services-drive-v2-rev5-1.7.2-beta.jar
|
90.4 kB
|
google-http-client-1.10.3-beta.jar
|
215 kB
|
google-oauth-client-1.10.1-beta.jar
|
72.6 kB
|
google-oauth-client-servlet-1.10.1-beta.jar
|
37.9 kB
|
guava-11.0.1.jar
|
1.6 MB
|
jackson-core-asl-1.9.4.jar
|
223 kB
|
Estas librerías no solo
son de la API de google, también hay otras como lo es filedrop, que me permitió
usar el evento Drag & Drop del sistema operativo.
Las imágenes que utilicé
yo las edité con el programa Adobe Fireworks, pero las imágenes de los skin
fueron creadas por Freeman.
El paquete que usé fue Black Background Set by
Freeman
Para el proyecto usé 8
clases, la que tiene mayor peso es la de la interfaz gráfica, generada por
Netbeans
Clase
|
Tamaño
|
animarObjeto.java
|
2.0 kB
|
configuracion.java
|
4.2 kB
|
GUD.java
|
2.1 kB
|
maquinaSubidora.java
|
18.6 kB
|
mover.java
|
3.0 kB
|
objetoSubido.java
|
1.5 kB
|
paralelismo.java
|
3.9 kB
|
v0.form
|
64.6 kB
|
v0.java
|
78.7 kB
|
La clase donde se
desarrolla la mayor cantidad de tareas es en maquinaSubidora.java en la que se
conecta a Google Drive y recibe información desde la clase v0.
La compilación del archivo
consiste de tres elementos:
La carpeta de librerías,
el archivo GUD.jar para ejecutar el programa, y la librería gUpDrive.dll que
debe estar en el mismo directorio que el programa.
Algunos de los import de
la clase maquinaSubidora.java son:
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.ChildList;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;
import java.awt.Desktop;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.*;
import
java.net.MalformedURLException;
import java.net.URI;
import
java.net.URISyntaxException;
import java.net.URL;
import
java.security.GeneralSecurityException;
import
java.util.ArrayList;
import
java.util.Arrays;
import
java.util.logging.Level;
import
java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
Por otra parte, esta
aplicación es multihilo o MultiThread. Tiene 3 hilos principales:
1. El hilo de ejecución principal, desde que se inicia el
programa hasta que termina
2. Un segundo hilo, en el que se ejecutan todas las
animaciones que se ven en la ventana
3. El hilo del momento en el que se están subiendo los
archivos.
De no ser por esto, el
programa se bloquearía cada vez que se sube un archivo, y volvería a estar
activo hasta finalizar la subida, lo cual no es muy conveniente porque esto
imposibilita a posibles tareas que requiera hacer el usuario.
Para lograr esto, usé la
clase paralelismo.java que a su vez es una subclase de SwingWorker, de la cual
copio una de las versiones de su código:
package gud;
import
java.awt.datatransfer.UnsupportedFlavorException;
import
java.io.IOException;
import
javax.swing.SwingWorker;
public class paralelismo extends
SwingWorker<String, Void> {
v0 ventana;
int accion;
// ▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼
public paralelismo(v0
ventana, int accionRecibida) { //1 subir desde portapapeles
this.ventana = ventana;
this.accion = accionRecibida;
}
// ▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼
void acciones() throws
UnsupportedFlavorException, IOException {
if (accion == 1) {
if
(ventana.hayConexion()) {
ventana.uploader.subirDesdePortapapeles(); // Intenta
subir la imágen desde el portapapeles
ventana.getjList1().setModel(ventana.uploader.obtenerSubidos());
//
le pasa al modelo todos los subidos
ventana.getjList1().setSelectionInterval(0,
ventana.getjList1().getModel().getSize() - 1);
//int[] a = {0,ventana.getjList1().getModel().getSize()-1};
// obtiene la cantidad de elementos menos 1 del modelo
//
ventana.getjList1().setSelectedIndices(a); // selecciona todos los elementos
ventana.getjButton1().setEnabled(true);
} else {
ventana.getjLabel3().setText("No hay
conexión a internet");
}
}
if (accion == 3) {
if
(ventana.hayConexion()) {
ventana.ejecutar(4);
ventana.uploader.subirCola();
//int[] a =
{0,ventana.getjList1().getModel().getSize()-1}; // obtiene la cantidad de
elementos menos 1 del modelo
//
ventana.getjList1().setSelectedIndices(a); // selecciona todos los elementos
ventana.getjButton4().setEnabled(true);
} else {
ventana.getjLabel3().setText("No hay
conexión a internet");
}
}
if (accion == 2) { // No importa
si hay conexión a internet o no, esta operación debe estar disponible
ventana.getjList1().removeAll();
// Obtiene los enlaces formateados
boolean c0 =
ventana.getjCheckBox0().isSelected(); // lista
boolean c1 = ventana.getjCheckBox1().isSelected();
//
hotlink
boolean c2 =
ventana.getjCheckBox2().isSelected(); // thumbnail html
boolean c3 =
ventana.getjCheckBox3().isSelected(); // thumbnail bbcode
boolean c4 =
ventana.getjCheckBoxMostrarSeparadores().isSelected(); // asteriscos
separadores ****...
boolean c5 =
ventana.getjCheckBox7().isSelected(); // tag <br />
String formateados =
ventana.uploader.obtenerEnlacesFormateados(ventana.getjList1().getSelectedValues(),
c0, c1, c2, c3, c4, c5);
//System.out.println(ventana.getjList1().getSelectedValues().length);
ventana.getjTextPane1().setText(formateados);
}
}
// ▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼
@Override
protected String
doInBackground() throws UnsupportedFlavorException, IOException {
acciones();
return "Operacion
finalizada";
}
// ▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼
@Override
public void done() {
}
// ▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼▲▼
}
Bueno yo soy estudiante
del Instituto Tecnológico de Costa Rica y busco sacarme la carrera de
Ingeniería en Computación, por lo que no tengo tiempo para desarrollar
proyectos. Actualmente estoy teniendo problemas económicos por lo que tuve que
salir este semestre a trabajar para poder ingresar nuevamente.
A veces aprovecho para
practicar y desarrollar un poco y de ello se deriva este proyecto, así como la
renovación de mi blog.
Algunos de los proyectos
que podrían (o no) interesarte son:
1. Blog: Es
donde publico material, información y opiniones.
2. Código: Proyectos
programados en la universidad. Van desde ensamblador hasta Python.
3. Sobre
la carrera: Información sobre los cursos que debo aprobar para ser
ingeniero.
4. COMPDES: Viaje a
otros países centroamericanos.
5. Tutoriales:
Algunos documentos sobre mi experiencia con diferentes lenguajes de
programación.
Para acceder a todas las
entradas del blog pueden acceder al siguiente enlace.
Mis proyectos e ideas los
publico en el tag de ideas. El proyecto gUpDrive lo tenía en mente desde la
publicación de esta
entrada
Este proyecto tiene una
licencia Safe Creative del tipo que se especificará a continuación.
Licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0:
1. Se puede copiar y distribuir
2. No se puede hacer uso comercial
3. Se pueden hacer trabajos derivados bajo la misma
licencia
4. Se debe reconocer la autoría
El enlace a esta licencia
es el siguiente: https://www.safecreative.org/work/1303064723717-gupdrive
No hay comentarios:
Publicar un comentario