Etiqueta

Mostrando entradas con la etiqueta Aula Omnis. Mostrar todas las entradas
Mostrando entradas con la etiqueta Aula Omnis. Mostrar todas las entradas

22 de agosto de 2011

Activar el servidor FTP en Lion

Una de las características que Lion ha quitado con respecto a sus antecesores es el servidor FTP nativo, el cual podemos habilitar pero que por defecto no lo tenemos para nada a mano.

Para habilitarlo nos toca ir a la Terminal -cosa habitual- y poner este comando:
sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist
Por contra, para deshabilitarlo ponemos este:
sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist
Lo que en realidad estamos haciendo cuando lo habilitamos es decirle a Launchctl que añada el daemon FTP a los que inician con el sistema, ni más ni menos.
Fuente | MacOSXHints

27 de mayo de 2011

Primer curso completo de diseño de aplicaciones con Omnis Studio

Por fin contamos con un completo curso de programación en Omnis Studio,
he impartido en castellano, más información sobre el mismo en la web oficial de Omnis Studio.

16 de mayo de 2011

Primer evento Omnis Studio en Barcelona


El próximo sábado 28 de Mayo se da inicio a una serie de eventos organizados por NSCoder_BCN cuyo objetivo es el de mostrar cómo desarrollar aplicaciones para iOS. 

Todos los asistentes tendran ocasion de conocer y probar el potente framework RAID "Omnis Studio". Con el que es posible crear potentes aplicaciones cliente-servidor, para toda la gama de dispositivos iOS. Para ello, el director de producto y uno de los ingenieros de Omnis Italia se desplazarán a Barcelona, para darnos a conocer esta potente herramienta.

Rellene de inmediato el formulario de inscripción gratuita.

30 de marzo de 2011

¿Cómo localizar filas con valores duplicados en tablas de Oracle?


Por fin he dado con una solución práctica y sencilla para resolver éste problema, he aquí la solución:

SELECT NOMBRE,APELLIDO1,APELLIDO2
FROM BALUMNOS
GROUP BY NOMBRE,APELLIDO1,APELLIDO2
HAVING COUNT (*) > 1;

Esta sencilla sentencia SELECT devolverá las filas contenidas en la tabla BALUMNOS cuyos nombres y apellidos estén duplicados.

29 de marzo de 2011

La “Component Library”


El navegador o “Studio Browser” contiene muchas plantillas y asistentes (wizards) que nos facilitan la construcción de aplicaciones y como ya sabemos es posible cambiar o añadir contenidos, tanto sobre el “Studio Browser”, como sobre el “Component Store”. A continuación mostramos dos ejemplos: El primero se trata de una plantilla simple, mientras que en el segundo mostraremos como crear un sencillo asistente.

Primer ejemplo: Plantilla o “Template”, para la creación de un menú “Edición” personalizado.

1)     Pulse “botón-derecho” sobre la opción “Libraries” del navegador y escoja la opción “Show Comps.lbs”.
2)     Cree una nueva clase “Menú” y llámela “Edición”.
3)     Pulse “botón-derecho” sobre la clase recién creada y tras escoger la opción “Component Store Type…”, seleccione “Template”.

Pulse “doble-click” sobre la clase construida.

-->
 Añada el código siguiente según la opción correspondiente:

Deshacer: Standard menu command *Edit/11001 {Undo}
Cortar: Standard menu command *Edit/11002 {Cut}
Copiar: Standard menu command *Edit/11003 {Copy}
Pegar: Standard menu command *Edit/11004 {Paste}
Borrar: Standard menu command *Edit/11005 {Clear}
Seleccionar todo: Standard menu command *Edit/11006 {Select All}
Pegar desde archivo…: Standard menu command *Edit/11065 {Paste From File...}

4)     Finalmente oculte la librería de componentes (opción “Hide Comps.lbs”)

Ahora podrá encontrar bajo la opción “Class Wizard >> Menu… >> Templates”, una nueva opción denominada “Edción”, selecciónela y pulse el botón “Create” cada vez que desee añadirla a su biblioteca en construcción.

Segundo ejemplo: Asistente o “Wizard” para la creación de un menú “Archivo” personalizado.

1)     Pulse “botón-derecho” sobre la opción “Libraries” del navegador y escoja la opción “Show Comps.lbs”.
2)     Cree una nueva clase “Menú” y llámela “Archivo”.
3)     Pulse “botón-derecho” sobre la clase recién creada y tras escoger la opción “Component Store Type…”, seleccione “Wizard”.
4)     Cree una nueva clase “Object” y llámela “CreaMenuArchivo”
5)     Añada un método al objeto, llámelo “$start” y asígnele el código siguiente, así como las variables locales y de parámetros utilizadas al efecto.

De parámetro

pRef                               Item reference
pWindowClass              Character
pMenuLineText             Character

Variables locales

lAplicacion                    Character
lMethodTextRef             Item reference
lRefLine                         Item reference

Método

Do pRef.$title.$assign('Archivo')

Do pRef.$methods.$findname('$setup()') Returns lMethodTextRef

Do pRef.$methods.$remove(lMethodTextRef) Returns #F

Prompt for input Introduzca el nombre de su aplicación: /Nombre de la aplicación//15 Returns lAplicacion

If flag true

      Do pRef.$objs.$add(con('Registrar ',lAplicacion,'...')) Returns lRefLine

      Do lRefLine.$methods.$add('$event')

      Do lRefLine.$methods.$findname('$event') Returns lMethodTextRef

      Do lMethodTextRef.$methodtext.$assign(con("Do $prefs.$serialise(kTrue,'Datos de registro",lAplicacion,"',24)")) Returns #F

      Do pRef.$objs.$add('')

      Do pRef.$objs.$add(con('Imprimirá en "',sys(24),'"...')) Returns lRefLine

      Do lRefLine.$methods.$add('$event')

      Do lRefLine.$methods.$findname('$event') Returns lMethodTextRef

      Do lMethodTextRef.$methodtext.$assign("Standard menu command *File/11090 {Print Destination '$'...}") Returns #F

      Do pRef.$objs.$add('Ajustar página...') Returns lRefLine

      Do lRefLine.$methods.$add('$event')

      Do lRefLine.$methods.$findname('$event') Returns lMethodTextRef

      Do lMethodTextRef.$methodtext.$assign("Standard menu command *File/11064 {Page Setup...}") Returns #F

      Do pRef.$objs.$add('Imprimir') Returns lRefLine

      Do lRefLine.$methods.$add('$event')

      Do lRefLine.$methods.$findname('$event') Returns lMethodTextRef

      Do lMethodTextRef.$methodtext.$assign("Print top window") Returns #F

      Do pRef.$objs.$add('Imprimir informe guardado...') Returns lRefLine

      Do lRefLine.$methods.$add('$event')

      Do lRefLine.$methods.$findname('$event') Returns lMethodTextRef

      Do lMethodTextRef.$methodtext.$assign("Standard menu command *File/11079 {Print Report From Disk... }") Returns #F

End If

Tras esto sólo nos quedará añadir un método al menú “Archivo” creado anteriormente, al que denominaremos “$setup()”, con el código siguiente:

Variables locales

lObjeto                           Object                    ComponentLibrary.CreaMenuArchivo

Método

Do lObjeto.$start($cclass().$ref)

6)     Finalmente oculte la librería de componentes (opción “Hide Comps.lbs”)

Ahora podrá encontrar bajo la opción “Class Wizard >> Menu…”, una nueva opción denominada “Archivo”, tras seleccionarla y pulsar el botón “Create” se le solicitará un nombre de aplicación, que será utilizado para componer la opción “Acerca de..” del menú “Archivo”.
 

11 de febrero de 2011

Uso del método $search


Uno de los temas más debatidos en Omnis Studio, es como moverse a través de una lista de modo eficaz. El “blog” de Bastiaan, recogía un artículo dedicado a esto que me ha parecido muy esclarecedor, por lo que me he decido a traducirlo al castellano y publicarlo en el blog de “Experiencias con Omnis Studio”.

Por lo que debemos empezar por dar las gracias a Bastiaan Olij y a Kelly Burgess por sus aportaciones.
Desde muy temprano Omnis nos ha provisto de funciones 4GL que nos permitían buscar y seleccionar líneas en una lista, pero en Omnis Studio, disponemos de un potente método denominado $search. Por supuesto podrá seguir usando los comandos 4GL tradicionales. Sin embargo enseguida notará que puede conseguir mejores resultados si hace uso del método $search. A continuación se muestran algunos ejemplos, pero antes debemos explicar que el método $search, consta de los siguientes 5 parámetros:

  1. El primero, es la búsqueda en sí misma, un cálculo que será avaluado para cada línea de la tabla objeto de búsqueda. Podrá usarse “$ref” como puntero hacia la línea que está siendo evaluada.
  2. El segundo parámetro, determinará si la búsqueda deberá realizarse desde el principio. Si es “kTrue” la búsqueda comenzará desde la línea 1. No obstante es importante hacer notar, que si la línea actual es “0”, la búsqueda siempre comenzará desde el principio.
  3. El tercero nos permitirá indicar si la búsqueda deberá afectar sólo a las líneas actualmente seleccionadas o por el contrario a toda la lista. Si es “kTrue” sólo las líneas actualmente seleccionadas serán evaluadas.
  4. El cuarto parámetro nos permitirá marcar las líneas encontradas como seleccionadas.
  5. Finalmente, un quinto parámetro nos permitirá, realizar el proceso inverso al descrito en el parámetro anterior, es decir nos permite marcar las líneas halladas como no seleccionadas.

Éste primer ejemplo, nos permite localizar la línea que cumple con los criterios de búsqueda especificados:

; Siempre será necesario hacer uso de los 5 parámetros
If lvMiLista.$search($ref.MiColumna = 'Buscame',ktrue,kfalse,kfalse,kfalse)>0
  ; La encontré
Else
  ; No existe
End If

 Selección de las líneas coincidentes con el criterio de búsqueda.

; Se usan los valores predeterminados para los parámetros
Do lvMiLista.$search($ref.MiColumna = 'Buscame')

Seleccionando todas las líneas.

Do lvMiLista.$search(kTrue)

Anulando la selección de todas las líneas.

; En este caso usamos un pequeño truco para anular la selección de sólo las líneas seleccionadas
Do lvMiLista.$search(kFalse,kTrue,kTrue)

Recorriendo las líneas seleccionadas.

; Aunque también es posible usar lvMiLista.$first(kTrue), poner $line a 0 nos ahorrará una línea de código
Calculate lvMiLista.$line as 0 ;; para comenzar desde el principio
While lvMiLista.$next(lvMiLista.$line,kTrue)
  ; Lo que quiera hacer
End While

Recorriendo las líneas coincidentes con el criterio de búsqueda, pero sin cambiar su estado actual.

Calculate lvMiLista.$line as 0 ;; para comenzar desde el principio
While          
lvMiLista.$search($ref.MiColumna='Buscame',kfalse,kfalse,kfalse,kfalse)>0
  ; Lo que quiera hacer
End While

Y, finalmente, un interesante procedimiento que le permitirá localizar las líneas en una lista, de modo mucho más rápido que usando un $search, pero con las siguientes dos limitaciones:

  1. La columna objeto de búsqueda deberá contener un valor único.
  2. La lista deberá estar ordenada por la columna objeto de búsqueda.

Evidentemente la necesidad de tener que ordenar la lista previamente, rebajará la ganancia de rendimiento, pero si ya se han recuperado los datos ordenados o si se deben realizar muchas búsquedas, tal sobrecarga no tendrá importancia alguna, el método expuesto a continuación forma parte de una clase “table”, pero también podría estar en una clase “object” o “code”, a la que pasar la lista a tratar como un parámetro:

tTableClass.$quickSearch(char pvNombreColumna, fieldref pvValor,
       int pvPrimeraLinea=1, int pvUltimaLinea=$cinst.$linecount)
--
;; Algoritmo de búsqueda basado en los conocidos “QuickSort” y “QuickSearch”
;; Recuerde que la lista debe estar ordenada y la columna debe contener valores únicos

If pvPrimeraLinea>pvUltimaLinea ;; No hay lista
  Calculate $cinst.$line as 0
  Quit Method 0
End If

If $cinst.[pvPrimeraLinea].[pvNombreColumna]=pvValor
  Calculate $cinst.$line as pvPrimeraLinea
  Quit Method pvPrimeraLinea
Else If pvPrimeraLinea=pvUltimaLinea|$cinst.[pvPrimeraLinea].[pvNombreColumna]>pvValor ;; No está en la lista
  Calculate $cinst.$line as 0
  Quit Method 0
End If

If $cinst.[pvUltimaLinea].[pvNombreColumna]=pvValue
  Calculate $cinst.$line as pvUltimaLinea
  Quit Method pvUltimaLinea
Else If pvPrimeraLinea+1=pvUltimaLinea|$cinst.[pvUltimaLinea].[pvNombreColumna];; No está en la lista
  Calculate $cinst.$line as 0
  Quit Method 0
End If

; Si se encuentra entre la primera y la última
Calculate lvLineaIntermedia as pvPrimeraLinea + ((pvUltimaLinea-pvPrimeraLinea)/2)
If lvLineaIntermedia=pvPrimeraLinea
  Calculate lvLineaIntermedia as lvLineaIntermedia+1
Else if lvLineaIntermedia=pvUltimaLinea ;; ¿Podría suceder?
  Calculate lvLineaIntermedia as lvLineaIntermedia-1
End If

If $cinst.[lvLineaIntermedia].[pvNombreColumna]=pvValor
  Calculate $cinst.$line as lvLineaIntermedia
  Quit Method lvLineaIntermedia
Else If $cinst.[lvLineaIntermedia].[pvNombreColumna]>pvValor
  ;  Localizada en la zona alta de la lista
 QuitMethod $cinst.$quickSearch(pvNombreColumna,pvValor,pvPrimeraLinea+1,lvLineaIntermedia-1)
Else
  ;  Localizada en la zona baja de la lista
 QuitMethod $cinst.$quickSearch(pvNombreColumna,pvValor,lvLineaIntermedia+1,pvUltimaLinea-1)
End If

Ahora podrá hacer uso del “quicksearch”, mediante simplemente hacer un:

Calculate lvValor as 'MiValorUnico'
Do lvMiLista.$quickSearch('MiColumna',lvValor)

3 de febrero de 2011

Conexión JDBC de Omnis Studio 5.1 a FileMaker 11


Acabo de conectar con éxito, en mi iMac a una fuente de datos FileMaker 11 desde Omnis Studio 5.1, a continuación explico los pasos que he dado:

  1. Copio el controlador JDBC de FileMaker 11 (fmjdbc.jar) sobre la carpeta "/Librería/Java/Extensions".

  2.  Activo la opción "Compartir JDBC/ODBC" de FileMaker.

  3. Creo la sesión mediante el SQL Browser de Omnis Studio, para la base de datos compartida mediante FileMaker, (en mi caso denominada "Prueba") tal y como se muestra en la siguiente imagen.


Y eso es todo, el atributo "$codepage" está fijado a "kUniTypeNativeCharacters" (valor por defecto, bajo la pestaña "Advanced") y todos los caracteres se visualizan perfectamente.


19 de enero de 2011

Creación y uso de una sesión con Oracle



- Instalación del cliente:

1) Sobre la instalación del cliente Oracle en Mac OS X, consulte la nota técnica Cliente Oracle
 

2) Crearemos los parámetros necesarios en el archivo "tnsnames.ora" a fin de que el cliente Orcale pueda conectarse con la base de datos (en nuestro ejemplo la llamaremos "BASEORA"

- Creación de la biblioteca:

1) Crearemos una nueva biblioteca Omnis, a la que llamaremos "Sesión"


2) Añadiremos una clase "schema" en correspondencia con una tabla existente en nuestra base de datos Orcale (para nuestro ejemplo será "BDIREC"


3) Añadiremos una clase "table" (en nuestro ejemplo la llamaremos "Tabla") y asignaremos en su propiedad "sqlclassname" el esquema "BDIREC"

En "Starup_Task" crearemos las siguientes variables:

4) La variable Task, "taSesion" de tipo "Object" y con subtipo "ORACLE8SESS" y las variables Class, "clEsquema" y "clTabla" de tipo "List", a ésta última le añadiremos el "subtype" "Tabla".
 

- Conexión simple:

Añadiremos (bajo el método $construct, del "Starup_Task")


5) Do taSesion.$logon('BASEORA','usuario','contraseña','nombresesión')


- Si deseamos usar un "pool" de conexiones:

5) Do $extobjects.ORACLE8DAM.$objects.ORACLE8SESS.$makepool('Sesiones',10,'BASEORA','usuario',contraseña')

Cada vez que deseemos obtener una nueva conexión de entre las 10 disponibles usaremos:

6) Do clEsquemaPrueba.$sessionobject.$assign($sessionpools.Sesiones.$new())

- Uso de una clase esquema (schema)

6/7) Do clEsquema.$sessionobject.$assign(taSesion)
7/8) Do clEsquema.$select()
8/9) Do clEsquema.$fetch(kFetchAll)


- Uso de una clase tabla (table)

6/7) Do clTabla.$sessionobject.$assign(taSesion)
7/8) Calculate $clib.$tables.Tabla.$sqlclassname as 'BDIREC'
8/9) Do clTabla.$carga
9/10) Do clTabla.$sort(clTabla.NOMBREC)

En este último caso el método "$carga" es el encargado de leer la tabla y guardar su contenido en la lista "clTabla", tal y como sigue:

El método "$carga", se creará en la clase "Tabla", con el siguiente contenido:


1) Do $cinst.$select()
2) Do $cinst.$fetch(kFetchAll)

18 de enero de 2011

Uso del comando “SMTPSend”, caso práctico.


Partimos de la existencia de una tabla Oracle, que contiene las direcciones e-mail de posibles destinatarios del mensaje a enviar, lo haremos en sólo tres sencillos pasos.
Paso I.
Creamos una ventana, desde donde el usuario podrá seleccionar cada uno de los elementos del mensaje a enviar:

Las variables de entorno que usaremos serán las siguientes:
Class Variable                 Type                 Subtype
FileLog                           Object              FileOps
cListaDestinatarios         List                   
cAsunto                          Character           50
cMensaje                         Character           1000
cOrderAdjuntar               Boolean            

cAdjunto                         Character           100
Sentencia                         Object


Paso II.
El método $construct de la ventana:
Local Variable                 Type                                      Subtype
Condicion                        Character                                1000 
lStatus                             Short integer (0 to 255)         

;  Carga las direcciones e-mail de los posibles destinatarios DB-ORACLE

Do $sessions.[$sessions.$first().$name].$newstatement() Returns Sentencia

;  La variable Condicion contendrá la clausula where con las condiciones de la sentencia select de Oracle, en nuestro ejemplo, tomamos dicha clausula de la ya consignada en una queri denominada Bus_Alumnos.

Calculate Condicion as $queries.Bus_Alumnos.$extraquerytext
Do Sentencia.$execdirect(con("Select unique(EMAIL) from BALUMNOS ",Condicion)) Returns lStatus
Do Sentencia.$fetch(cListaDestinatarios,kFetchAll) Returns lStatus
Do cListaDestinatarios.$sendall($ref.$selected.$assign(kTrue))

;  Una vez cargada la lista cListaDestinatarios con las direcciones de e-mail, candidatas, nos aseguramos de tener la primera línea de la lista seleccionada, y las variables usadas para adjuntar un documento en sus valores iniciales.

Do cListaDestinatarios.$line.$assign(0)
Calculate cOrdenAdjuntar as 0
Calculate cAdjunto as ''


Paso III.
Crearemos un control de eventos para el botón: Adjuntar archivo
On evClick
Do FileOps.$getfilename(cAdjunto) Returns #F
If flag false
Calculate cOrdenAdjuntar as 0
Calculate cAdjunto as ''
Do $cobj.$redraw()
End If

Otro para el botón: Cancelar

On evClick
Close top window

Y finalmente



El evento para el botón: Enviar

Local Variable                 Type                                      Subtype
lArchivoBin                    Binary                                    n/a
lBinData                          Binary                                    n/a
lCharData                        Character                                1000000000
lCharSet                          Character                                50
lContentSubType           Character                                50
lContentType                 Character                                50
lEncoding                        Character                                1000000000
lFileName                        Character                                50
lLevel                              Short integer (0 to 255)
lNimeList                        List
lNombreArchivo             Character                                50
                                                          
On evClick

;  Primero eliminaremos de la lista las direcciones e-mail, que el usuario a des-seleccionada sobre la lista de candidatos.

Set current list cListaDestinatarios
For each line in list from 1 to #LN step 1
If cListaDestinatarios.$selected=kFalse
Delete line in list
End If
End For

;  Comprobaremos si el usuario ha seleccionado (o no) un documento para adjuntar al e-mail, pues el comando SMTPSend cambiará dependiendo de ésto.

If cAdjunto<>''
Do lNimeList.$define(lLevel,lContentType,lContentSubType,lFileName,lCharData,lBinData,lCharSet,lEncoding)
Do lNimeList.$add(0,'multipart','mixed')
Do lNimeList.$add(1,'text','plain',,cMensaje,,,)
Calculate lNombreArchivo as mid(cAdjunto,rpos(':',cAdjunto)+1,50)
Do FileLog.$openfile(cAdjunto)
Do FileLog.$readfile(lArchivoBin)
Do FileLog.$closefile()
Do lNimeList.$add(1,'application','octet-stream',lNombreArchivo,,lArchivoBin,,,)
SMTPSend ('smtp.miservidor.local','mi.direccion@ miservidor.es',cListaDestinatarios,cAsunto,lNimeList,,,'Universidad de Salamanca',,'1') Returns Estado
Else
SMTPSend ('smtp. miservidor.local',mi.direccion@ miservidor.es',cListaDestinatarios,cAsunto,cMensaje,,,'Universidad de Salamanca',,'1') Returns Estado
End If
Close top window

Y eso habrá sido todo, sólo indicar que el objeto, que muestra los destinatarios en la ventana de composición del mensaje, es de tipo kCheckBoxList, para facilitar al usuario, des-seleccionar direcciones e-mail.

Un cordial saludo, en especial a Case Software, Victor y Pepe, quienes se manifiestan como seguidores de éste blog.

Manual de Programación Omnis Studio en Castellano


También disponible en formato PDF.


Recuerde que:  Adquiriendo una licencia o una actualización de cualquier producto Omnis Studio a través del distribuidor oficial (http://www.softpi.com), recibirá una copia en formato PDF.

17 de enero de 2011

Favoritos para "consultas sql dinamicas"

Hace algún tiempo que publiqué en este "blog" un ejemplo para crear consultas sql, ahora veremos como añadir a la ventana de resultados una nueva funcionalidad que nos permita guardar a modo de "favoritos" las búsquedas realizadas, para usarlas en otras ocasiones sin tener que reescribirlas.

El primer paso será crear un nuevo objeto sobre la ventana de resultados, un menú desplegable cuyo aspecto sería el siguiente:


En el procedimiento $construct de la ventana resultados añadiremos la siguiente secuencia:

; Carga menú de favoritos
Do cFavoritos.$define(cFavNombre,cFavConsulta)
Test if file exists {[con(mid(sys(115),1,pos(':',sys(115))),iBusqueda,'.txt')]}
If flag true
Set import file name {[con(mid(sys(115),1,pos(':',sys(115))),iBusqueda,'.txt')]}
Prepare for import from file {Delimited (tabs)}
Import data cFavoritos
Close import file
End If

Do cFavoritos.$addbefore(1,'Favoritos')
Do cFavoritos.$add('Añadir...')
Do cFavoritos.$add('Examinar...')
Do cFavoritos.$line.$assign(1)


Cuando el usuario seleccione una opción de éste menú podrá suceder lo siguiente:

On evClick
Switch cFavoritos.cFavNombre

Case 'Añadir...'
Prompt for input De nombre a la selección actual/Favoritos/3005/50 Returns cFavNombre (Cancel button,Prompt above entry)
If flag true
Do cFavoritos.$addafter(1,cFavNombre,$clib.$queries.[iBusqueda].$extraquerytext)
; Guarda favoritos en el disco
Set current list cFavoritos
If #LN>3
Set print or export file name {[con(mid(sys(115),1,pos(':',sys(115)))
,iBusqueda,'.txt')]}
For each line in list from 2 to #LN-2 step 1
Transmit text to print file {[cFavoritos.cFavNombre][chr(9)][cFavoritos.cFavConsulta][chr(9)][chr(13)]}
End For
Close print or export file
End If
End If
Case 'Examinar...'
Open window instance Favoritos (iBusqueda)

; Recarga favoritos
Set import file name {[con(mid(sys(115),1,pos(':',sys(115))),iBusqueda,'.txt')]}
Prepare for import from file {Delimited (tabs)}
Import data cFavoritos
Close import file
Do cFavoritos.$addbefore(1,'Favoritos')
Do cFavoritos.$add('Añadir...')
Do cFavoritos.$add('Examinar...')
Do cFavoritos.$line.$assign(1)
Do $root.$redraw()

Default
Do $clib.$queries.[iBusqueda].$extraquerytext.$assign(cFavoritos.cFavConsulta)
Do iVerList.$definefromsqlclass(iBusqueda)
Do iVerList.$sessionobject.$assign(iSessionObj) Returns #F
Do iVerList.$select() Returns lStatus
Do iVerList.$fetch(kFetchAll) Returns lStatus
Do iVerList.$line.$assign(1)
Calculate cRecordList as con(iVerList.$linecount,' registros en seleción')
Do $root.$redraw()
End Switch

Do cFavoritos.$line.$assign(1)
Do $cwind.$objs.Favoritos.$redraw()


La ventana para la gestión de favoritos (opción examinar) mostraría el siguiente aspecto:


La programación para esta ventana sería como sigue:

En el $construct de la ventana:

Do iListFavor.$define(iFavNombre,iFavConsulta)
Set current list iListFavor
Set import file name {[con(mid(sys(115),1,pos(':',sys(115))),pBusqueda,'.txt')]}
Prepare for import from file {Delimited (tabs)}
Import data iListFavor
Close import file
Enter data
If flag true
; Guarda favoritos en el disco
Set print or export file name {[con(mid(sys(115),1,pos(':',sys(115))),pBusqueda,'.txt')]}
For each line in list from 1 to #LN step 1
Transmit text to print file {[iListFavor.iFavNombre][chr(9)][iListFavor.iFavConsulta][chr(9)][chr(13)]}
End For
Close print or export file
End If
Close top window


Para la opción "mover arriba":

On evClick ;; Event Parameters - pRow( Itemreference )
Calculate iListFavor.$line as $cwind.$objs.favoritos_datagrid_1016.$gridvcell-1
If iListFavor.$line>1&iListFavor.$linecount>1
Load from list
Do iListFavor.$addbefore(iListFavor.$line-1,iFavNombre,iFavConsulta)
Do iListFavor.$remove(iListFavor.$line+1)
Do $cwind.$objs.favoritos_datagrid_1016.$redraw()
End If


Para la opción "mover abajo":

On evClick
Calculate iListFavor.$line as $cwind.$objs.favoritos_datagrid_1016.$gridvcell-1
If iListFavor.$line
Load from list
Do iListFavor.$addafter(iListFavor.$line+1,iFavNombre,iFavConsulta)
Do iListFavor.$remove(iListFavor.$line)
Do $cwind.$objs.favoritos_datagrid_1016.$redraw()
End If


Y por último para la opción "eliminar":

On evClick
Calculate iListFavor.$line as $cwind.$objs.favoritos_datagrid_1016.$gridvcell-1
If iListFavor.$line>0
Do iListFavor.$remove(iListFavor.$line)
Do $cwind.$objs.favoritos_datagrid_1016.$redraw()
End If


Y eso será todo, el sistema contendrá en archivos de texto plano, las preferencias o favoritos de las búsquedas seleccionadas permitiendo su posterior uso, con tan sólo seleccionarlas desde el menú, cada búsqueda diferente tendrá su propio archivo de texto plano.

13 de enero de 2011

Herramienta "ad hoc"

La herramienta de informes "ad hoc "

Se trata de una versión localizada al castellano de esta herramienta proporcionada por Omnis, para la generación rápida de informes y consulta de datos, mediante SQL.

El acceso a la base de datos se realiza mediante la DAM Omnis SQL para tener acceso a un archivo de datos de Omnis. La utilidad comprueba las sesiones abiertas con el servidor de datos y utiliza esta (independientemente de que servicio se trate Oracle, MySQL, etc) para presentar las tablas de datos que contenga.

Los informes que se generan son iguales que los presentados por la aplicación estándar "ad hoc" por lo que su manejo es idéntico al que se describe en el manual de Omnis para esta herramienta. Para usarla deberá colocar la librería adjunta en la carpeta de inicio (Startup).

Descargar librería

12 de enero de 2011

Aplicaciones modulares

Al diseñar una aplicación, es posible que deseemos modularla mediante la creación de una biblioteca que contenga todos los módulos de ventanas, informes y métodos.
Cada módulo puede tener sus propios menús y barras de herramientas. Un ejemplo podría ser una aplicación de gestión académica, con las preinscripciones, matriculas y expedientes.
En una aplicación totalmente modular, donde el usuario cambia constantemente entre módulos, no es fácil asegurarse de que el usuario vea correctamente los menús y herramientas para el módulo en uso. En un entorno, multi-ventana, el control de esta a veces puede ser difícil. Afortunadamente Omnis Studio permite la creación de múltiples “tasks” o tareas que permiten automatizar el proceso de creación de aplicaciones modulares.
Observe el ejemplo siguiente en el que, en una sola biblioteca se están ejecutando tres tareas: La “Startup_Task” y dos tareas más “Task1” y “Task2”. La tarea de inicio, que se abre automáticamente cuando se abre la biblioteca, contiene una ventana “Acerca de”. Las otras dos tareas contienen cada una, una ventana, un menú y una barra de herramientas. Cuando el usuario selecciona una ventana de “Task1” o de “Task2”, Omnis mostrará automáticamente las herramientas (toolbar) y los menús que correspondan a cada tarea.

Cuando la biblioteca se abre, la tarea inicial se ejecuta (Startup_Task) para mostrar la ventana “Acerca de” entonces se abren las demás tareas, cada una de los cuales abre su ventana, instala su menú y su barra de herramientas. La tarea de inicio concluye una vez que la propia ventana “Acerca de” se cierre.
Para abrir las dos tareas, usted deberá introducir la siguiente secuencia de instrucciones en el método $construct() de la tarea inicial.
Open window instance AboutWindow
Open task instance MyTaskClass1/Task1
Open task instance MyTaskClass2/Task2
Close task instance LibraryName ;; cierra la instancia Startup_Task

Cada tarea tiene una propiedad $autoactivate, que permite a la misma tomar el control, cuando el usuario actúa sobre la ventana que la contiene. Si la propiedad se establece en “false”, la ventana no llegará a mostrarse. Para que se active de manera automática, será necesario fijar la siguiente secuencia en el $construct() de cada tarea.
Do $ctask.$autoactivate.$assign(kTrue)
Para asegurarse de que los menús y barras de herramientas se muestren y oculten al cambiar de tarea, necesitará establecer la propiedad $local en cada clase. Al activar el “modo local” para cada menú y barra de herramientas que posee la tarea, Omnis los esconderá y mostrará automáticamente.
El ejemplo que se muestra a continuación, indica como establecer la propiedad $local desde el procedimiento $construct() de cada tarea:
; Método $construct() para la task1...
Do $menus.MyMenuClass1.$open(‘Menu1’) Returns iMenuRef
Do iMenuRef.$local.$assign(kTrue)
Do $toolbars.MyToolbarClass1.$open(‘Toolbar1’) Returns iToolRef
Do iToolRef.$local.$assign(kTrue)
Do $windows.MyWindowClass1.$open(‘Window1’) Returns iWinRef
Y exactamente lo mismo para la otra tarea.
; Método $construct() para la task2...
Do $menus.MyMenuClass2.$open(‘Menu1’) Returns iMenuRef
Do iMenuRef.$local.$assign(kTrue)
Do $toolbars.MyToolbarClass2.$open(‘Toolbar1’) Returns iToolRef
Do iToolRef.$local.$assign(kTrue)
Do $windows.MyWindowClass2.$open(‘Window1’) Returns iWinRef
Esta funcionalidad hará que los menús y barras de herramientas cambien automáticamente al cambiar de tarea.

¿Cómo permitir al usuario eliminar filas en un "Data Grid"/"Smart List"?

Descripción del problema:

Pongamos como ejemplo la siguiente tabla de datos, representada en un objeto tipo "kdatagrid":

Do cTablaEdit.$definefromsqlclass(iTituVen)
Do cTablaEdit.$sessionobject.$assign(iSessionObj) Returns #F
Do cTablaEdit.$select() Returns lStatus
Do cTablaEdit.$fetch(kFetchAll) Returns lStatus
Do cTablaEdit.$line.$assign(1)
Do cTablaEdit.$smartlist.$assign(kTrue)
If cTablaEdit.$linecount=0
Do cTablaEdit.$add()
End If

El problema parte de que mientras el usuario se mueve entre las celdas de la tabla, el atributo "cTablaEdit.$line" no cambia. En el ejemplo deseamos que el usuario pueda seleccionar la fila a borrar pulsando la tecla "F5", el asunto entonces es: ¿Cómo saber que número de fila (cTablaEdit.$line) debemos eliminar?

Solución:

On evCellChanged
Do cTablaEdit.$line.$assign(pVertCell)
On evKey
If pSystemKey=5
Yes/No message Eliminar registros {¿Desea realmente eliminar la línea de la tabla?}
If flag true
Do cTablaEdit.$remove(cTablaEdit.$line)
Do $root.$redraw()
End If
Process event and continue (Discard event)
End If

El evento evCellChanged, mantendrá seleccionada la línea o fila a borrar, de tal modo que el prodedimiento Do cTablaEdit.$dowork() actualizará finalmente la tabla en el servidor eliminando las filas marcadas para borrar.

No he encontrado un método mejor para solucionar este problema, no obstante (si usted querido lector lo tiene a bien), tal vez pueda sugerir algún otro procedimiento, de ser así lo ánimo a dejar su comentario en este blog.

Gracias por su atención.

11 de enero de 2011

Ajuste de la resolución de pantalla

Descripción del problema:

A menudo nos encontramos con diferentes monitores y diferentes configuraciones de resolución, además algunos usuarios prefieren una resolución menor de pantalla a fin de aumentar el tamaño de los objetos representados (no sólo el texto), especialmente aquellos que tengan alguna dificultad de visión.

Para resolver esta cuestión las aplicaciones desarrolladas con Omnis Studio deberían ser capaces de permitir al usuario elegir la resolución que deseen. Afortunadamente Omnis Studo incorpora los elementos necesarios para realizar este proceso, tan sólo se debe tener en cuenta que cuando se asignen estas preferencias se debe cerrar y reabrir la biblioteca para que surtan efecto.

A continuación describo en detalle un procedimiento que podría incorporarse a las opciones de preferencias de nuestra aplicación Omnis Studio, el ejemplo muestra un objeto visual que permitirá al usuario hacerse una idea del tamaño que tendrán sus ventanas tras aumentar o disminuir la resolución:


La ventana de preferencias podría ser de un estilo similar a este, mostrando (por ejemplo) un cuadro he indicadores de grado (Slider Control) para que el usuario modifique la resolución ha obtener según lo desee, no obstante tendremos que prefijar las resoluciones máximas y mínimas posibles, en nuestro caso las resoluciones posibles estarán entre 1.680x1.050 y 1.360x850. Para la resolución máxima (1.680x1.050) el rectángulo guía tendrá un tamaño de 130x220 ($height=130, $width=220).

Usaremos dos variables numéricas definidas para la clase "ventana de preferencias", las llamaremos “ZoomHori” y “ZoomVert”.

A continuación añadiremos al procedimiento $construct las siguientes líneas de código:

; Recoge el valor actual de resolución en pantalla
Do $cwind.$objs.ZoomHorizontal.$val.$assign($clib.$prefs.$hscale)
Calculate ZoomHori as $clib.$prefs.$hscale
Do $cwind.$objs.ZoomVertical.$val.$assign($clib.$prefs.$vscale)
Calculate ZoomVert as $clib.$prefs.$vscale
Do $cwind.$objs.NaviElement.$val.$assign($clib.$userinfo)
Calculate $cwind.$objs.ZoomHorizontal.$::min as 1360
Calculate $cwind.$objs.ZoomVertical.$::min as 850
Do $cwind.$bobjs.1053.$height.$assign(int((1680-$clib.$prefs.$hscale)/'6,40')+130)
Do $cwind.$bobjs.1053.$width.$assign(int((1050-$clib.$prefs.$vscale)/'3,33')+220)

Esto fijará la escala (o resolución) a los valores actuales y ajustará el tamaño del cuadro (ID=1053), lo que permitirá al usuario hacerse una idea aproximada de como se verán las ventanas en su pantalla.

Ahora debemos fijar los procedimientos asociados a las barras "Slider Control"

Para ZoomHorizontal:

On evNewValue
Calculate ZoomHori as pNewVal
Do $cwind.$bobjs.1053.$height.$assign(int((1680-ZoomHori)/'6,40')+130)

Para ZoomVertical:

On evNewValue
Calculate ZoomVert as pNewVal
Do $cwind.$bobjs.1053.$width.$assign(int((1050-ZoomVert)/'3,33')+220)

Finalmente debemos dejar ajustada la resolución que el usuario ha seleccionado, esto lo haremos al abandonar la clase "ventana de preferencias", (procedimiento $destruct) tal y como sigue:

; Establece nuevos valores de resolución en pantalla
Do $clib.$prefs.$hscale.$assign(ZoomHori)
Do $clib.$prefs.$vscale.$assign(ZoomVert)

Suelo incorporar este procedimiento en todas las aplicaciones que realizo, los usuarios agradecen disponer de un ajuste personalizado para cada aplicación.

Si encontráis útil la idea o tenéis otra mejor, os animo a que dejéis vuestros comentarios en el "blog", por mi parte seguiré incorporando alguna otra idea de interés general.

Un cordial saludo a todos los desarrolladores de Omnis Studio y en especial a los participantes del grupo programomnis.