Compilar Release APK para Phonegap 3.x

Hace algún tiempo estuve tratando de encontrar la manera de generar el APK de una aplicación móvil para Android que estaba desarrollando usando Phonegap. Esta herramienta te permite, mediante los comandos build y run, generar e instalar la aplicación en dispositivos Andoid:

phonegap local build android

o

phonegap local run android --device

Sin embargo, con estos comandos solamente se generan APK en modo Debug, los cuales no se pueden subir a la Play Store. Por ello necesitaba encontra la forma de compilar el proyecto en modo Release. Pero casi toda la información que encontraba mencionaba que debía hacer uso del servicio de Phonegap Build. Sigue leyendo

Mi escritorio de Manjaro

Minientrada

Hola. Ya tenía algo de tiempo de no escribir, y por cuestiones de tiempo, esta solo será una entrada breve, y en realidad nada técnica. Solo quería compartir mi escritorio de Manjaro Linux.

Desde hace unos 4 meses he instalado Manjaro Linux 0.8.5 con OpenBox en nuestra Laptop Dell Inspiron 1525, y debo decir que su uso ha sido bastante tranquilo y sin mayor inconveniente (“pretty straightforwad”, como dirían en inglés). La documentación es bastante buena, y si no existe para Manjaro, es posible basarse en la documentación de Arch, ya que esta es una distro derivada directamente de este.

En un inicio me vi tentado a volver a Gnome3, y de hecho lo instalé (y disfruté, jejeje), nuevamente sin mayor inconveniente. Pero luego de ver algunas imágenes de escritorios con OpenBox personalizados, me animé a darle una segunda probada, y debo decir que aunque no le he dedicado mayor tiempo, creo que finalmente he logrado montar algo que me gusta.

Mi escritorio

Mi escritorio

En la captura puede observarse el panel Tint2 que trae por defecto, pero que solo muestra los íconos de las aplicaciones, lo que deja bastante espacio libre, y la posibilidad de ver hasta unas 11 aplicaciones por escritorio (nótese que el panel está dividido en áreas, una por cada escritorio del sistema). A la derecha se muestra un despliegue de datos gracias a conky, tomado de esta página web. Cabe mencionar que aunque el diseño es para Debian, por el logo que se muestra en el reloj, en realidad lo tome porque me gustó la combinación de colores, ya que combina con la imagen de fondo del escritorio. Por cierto, tuve que desinstalar el conky que trae por defecto Manjaro, e instalar conky-lua desde los repositorios de AUR, usando Yaourt, ya que esta configuración hace uso de scripts Lua, para generar esos llamativos medidores circulares. La imagen de fondo no recuerdo de donde la tomé (no pertenece a mí, digo, por cuestiones de derechos de autor), pero me ha gustado bastante, creo que es del Antelope Canyon, de Estados Unidos.

Auto-suspender USB en Manjaro Linux

Hola nuevamente. Estos días he estado “topado” de trabajo y últimamente problemas, así que no había tenido mucho tiempo de escribir. Hace un mes, más o menos, me animé a probar otro sabor de Linux, llamado Manjaro, que es una distro basada en Arch Linux. Ha sido una experiencia interesante, ya que es un intermedio entre Ubuntu y Arch, en cuanto a amigabilidad con el usuario. Pero estos detalles quedan para otra ocasión…

Volviendo al tema, este sistema operativo lo instalé en una Laptop, y al ser una distribución más preparada, posee configuraciones de ahorro de energía que entran en vigencia automáticamente al desconectar el cargador de la computadora. Una de ellas, que me causó ciertos problemas, es la opción de auto-suspender USB, que hacía que mi ratón (mouse, por SEO y la transculturización) dejara de funcionar al dejarlo de utililizar. No entendía la razón, hasta que después de varios días, me di cuenta que esto sucedía solo si la Laptop estaba desconectada de la electricidad.

Aparentemente la opción de auto-suspender está configurada para deshabilitar el consumo de energía de los dispositivos conectados a puertos USB, después de 2 segundos sin usarlos.

Para deshabilitar la auto-suspensión de USB, hay dos opciones:

  • Deshabilitar la auto-suspensión por completo, abriendo el archivo /etc/laptop-mode/conf.d/usb-autosuspend.conf, y establecer el valor del siguiente parámetro (ojo, el parámetro ya existe):
    CONTROL_USB_AUTOSUSPEND=0
  • La segunda opción es crear una lista negra de los dispositivos USB que no se desean suspender. En este post se detalla como hacerlo (perdón, no he tenido tiempo de probar esta opción, jejeje).

Feliz semana :)

Crear botón de impresión en ReportViewer de ASP.NET WebForms

Hola nuevamente. Este post es una segunda versión del post titulado Imprimir reporte de ReportViewer desde otro navegador web que no sea IE. Entre las mejoras de esta nueva versión está que en vez de añadir un botón normal para la impresión fuera del ReportViewer, ahora se añade el botón de impresión dentro de la barra de herramientas del ReportViewer, y luce exactamente igual al botón propio del control. Además, con esta nueva versión también se logra que la impresión funcione en IE 9 y 10 en modo normal. La única desventaja es que hay que desactivar la renderización asíncrona y los postbacks asíncronos, para poder colocar el botón de impresión con jQuery, ya que se necesita alguna forma de saber en qué momento colocar el botón, y la única forma que encontré es hacerlo al momento de cargar la página web luego del postback en el que se solicita la generación del reporte, durante el evento load.

Los pasos para colocar nuestro botón de impresión personalizado en la barra de herramientas del ReportViewer son los siguientes:

    1. Incluir la librería jQuery en el encabezado de la página web:
      <script src="<%=Page.ResolveUrl("~/Scripts/jquery-1.7.1.min.js") %>" type="text/javascript"></script>
      
    2. Agregar el control de ReportViewer, desactivando el renderizado asíncrono y el postback asíncrono, y ocultando el botón de impresión:
      <rsweb:ReportViewer ID="ReportViewer1" runat="server" AsyncRendering="False" InteractivityPostBackMode="AlwaysSynchronous" ShowPrintButton="False">
      </rsweb:ReportViewer>
      
    3. Colocar en el encabezado de la página web el siguiente código JavaScript (el cual se explica un poco en los comentarios):
      // Guardando la URL de la imagen del botón imprimir. Esta imagen es una copia de la imagen mostrada en el ReportViewer, guardada en la carpeta de imágenes de la aplicación web.
      var urlImg = '<%=Page.ResolveUrl("~/Content/themes/base/minified/images/Print.gif") %>';
      
      // Función que se ejecuta una vez se ha terminado de cargar el DOM de la página web en el navegador
      $(document).ready(function () {
          colocarBtnImprimir();    // Colocar el botón de imprimir en la barra de herramientas del ReportViewer
          $("#BtnImprimir").click(imprimirDiv);  // Asignando la función "imprimirDiv" al evento click del botón de impresión
      });
      
      // Esta función coloca el botón de imprimir en la barra de herramientas del ReportViewer
      function colocarBtnImprimir() {
          var jqoBarraRpt = $('div#ReportViewer1_ctl05>div:first-child');    // Buscando el div que contiene la barra de herramientas del RportViewer
      
          if (jqoBarraRpt && jqoBarraRpt.length > 0    // Verificando que el DIV barra de herramientas fue encontrado,
              && jqoBarraRpt.find('#BtnImprimir').length <= 0) {    // y verificando que el botón de imprimir no existe ya
      
              // Colocando el botón de impresión, con una estructura similar a la que tiene el botón original en el ReportViewer
              jqoBarraRpt.append('<table cellpadding="0" cellspacing="0" ToolbarSpacer="true" style="display:inline;width:10px;"><tr><td></td></tr></table><div style="display:inline;font-family:Verdana;font-size:8pt;vertical-align:top;"><table cellpadding="0" cellspacing="0" style="display:inline;"><tr><td height="28px"><div"><div id="BtnImprimir"><table title="Print"><tr><td><img title="Print" src="' + urlImg + '" alt="Print" style="border-style:None;height:16px;width:16px;" /></td></tr></table></div><div disabled="disabled" style="display:none;border:1px transparent Solid;"><table title="Print"><tr><td><input type="image" disabled="disabled" title="Print" src="' + urlImg + '" alt="Print" style="border-style:None;height:16px;width:16px;cursor:default;" /></td></tr></table></div></div></td></tr></table></div>');
          }
      }
      
      // Función que se encarga de imprimir el reporte
      function imprimirDiv()
      {
          var divImprimir = $("div[id$='ReportDiv']").parent();    // Obteniendo el DIV que contiene el reporte a imprimir
          var newWin = window.open();    // Abriendo una nueva ventana del navegador
          newWin.document.open();    // Abriendo el documento de la nueva ventana, para escribir su contenido
          newWin.document.write('<html><head><style type="text/css">' + getAllStyleSheetsAsText() + '</style></head><body>' + divImprimir.html() + '</body>');
          newWin.document.close();
          newWin.print();
          newWin.close();
      }
      
      function getAllStyleSheetsAsText() {
          var cssText = '';
          var sheets = document.styleSheets;
          for (var c = 0; c < sheets.length; c++) {
              var sheet = sheets[c];
              if ((sheet.ownerNode || sheet.owningElement).id.endsWith('_ReportControl_styles')) {
                  var rules = sheet.rules || sheet.cssRules;
                  for (var r = 0; r < rules.length; r++) {
                      var cssRule = rules[r];
                      if ($.browser.msie) {
                          var cssText = cssText + cssRule.selectorText + '{' + cssRule.style.cssText.toLowerCase() + '}';
                      } else {
                          var cssText = cssText + cssRule.cssText;
                      }
                  }
              }
          }
          return cssText;
      }
      
    4. Finalmente, hay que agregar el estilo CSS para el botón de impresión, para que luzca igual al botón original del ReportViewer:
      #BtnImprimir {
          border: 1px solid transparent;
      }
      #BtnImprimir:hover {
          border: 1px solid rgb(51,102,153);
          background-color: rgb(221,238,247);
          cursor:pointer;
      }
      

Y ¡listo!. Ahora veremos que cada vez que se genere el reporte y se muestre la barra de herramientas del ReportViewer, se mostrará nuestro botón de impresión personalizado:

Botón de impresión

Botón de impresión

Lo único que tengo que mencionar es que aún no he probado la impresión de reportes con más de una página. Pero para reportes de una sola página parece funcionar correctamente.

Saludos.

SQL Server Snippets – Consultar roles y usuarios de una base de datos

El siguiente snippet sirve para obtener el listado de roles de una base de datos, con los usuarios que pertenecen a dicho rol:

SELECT
  p.name rol,
  p.principal_id id_rol,
  m.name usuario,
  m.principal_id id_usuario
FROM sys.database_role_members rm
  INNER JOIN sys.database_principals p
    ON rm.role_principal_id = p.principal_id
  INNER JOIN sys.database_principals m
    ON rm.member_principal_id = m.principal_id
ORDER BY p.name

La consulta devuelve un listado de roles y usuarios de la base de datos donde se ejecuta. Cabe mencionar que el listado contiene solamente los roles que están asignados a al menos un usuario (debido a los INNER JOIN), y que devuelve una fila por cada usuario y rol distinto. En este sentido, los usuarios que poseen más de un rol aparecerán repetidos en el listado. En otras palabras, si un usuario pertenece a N roles, entonces aparecerá repetido N veces en el listado, una vez por cada rol al que pertenece.

La consulta funciona (hasta donde yo he probado) en SQL Server 2005, 2008 y 2012.

Feliz día :)

Leer archivo de tabla de Visual Fox Pro (DBF) desde SQL Server

En mi trabajo, debido a que varios sistemas que se utilizan han sido desarrollados en Visual Fox, ha surgido la necesidad de leer los archivos de tabla (.DBF), desde SQL Server, para poder importar la información de los sistemas antiguos a los nuevos.

Existen varios driver para realizar esta tarea (dBase, ODBC, OleDB, etc.). En esta entrada me centraré en explicar como leer los archivos de tabla utilizando el driver de OleDB.

Primeramente, hay que instalar el driver OleDB en la computadora que alberga la instancia de SQL Server. El driver puede descargarse aquí. Si no me equivoco, no es necesario reiniciar la computadora ni los servicios de SQL Server luego de la instalación (puedo equivocarme, jejeje :)).

En segundo lugar, hay que asegurarse que el usuario que ejecuta la instancia de SQL Server, tenga permiso de lectura sobre el archivo de tabla DBF. Si se utiliza autenticación de Windows, entonces el usuario de Windows debe tener permiso de lectura sobre el archivo.

Finalmente, para leer el archivo, basta con hacer la lectura utilizando la función T-SQL llamada OPENROWSET, de la siguiente manera:

SELECT *  FROM OPENROWSET(
'VFPOLEDB.1',
'C:\ruta\del\archivo';'';'',
'SELECT * FROM NOMBRE_ARCHIVO')

Por ejemplo, para leer el archivo C:\Users\UsuarioPruebas\Documents\TABLA.dbf, la sentencia sería la siguiente:

SELECT *  FROM OPENROWSET(
'VFPOLEDB.1',
'C:\Users\UsuarioPruebas\Documents';'';'',
'SELECT * FROM TABLA')

El comando ha sido probado en SQL Server 2005, pero creería que también funciona para versiones posteriores (2008, 2012).

Feliz día :)

Presentación de FluentViewModel

Hola nuevamente. No me pude esperar, así que decidí presentarles mi proyecto para ASP.NET MVC: FluentViewModel. Espero subirlo a GitHub en un futuro cercano (es decir, no muy lejano, jejeje…), para que esté disponible para todo el mundo, y quien lo quiera mejorar pueda hacerlo.

¿Qué es FluentViewModel?

FluentViewModel es una interfaz fluida para definir modelos de vista en ASP.NET MVC usando C#, construida sobre FluentValidation.

FluentViewModel permite mapear las propiedades de un modelo existente a plantillas de editores de formulario y vistas, aprovechando las ventajas de las clases genéricas, notación lambda y la funcionalidad de autocompletar de Visual Studio, para facilitar a los programadores la creación de modelos de vista.

Por otra parte, FluentViewModel hace uso de las funcionalidades de FluentValidation para definir las validaciones necesarias a realizarse para los objetos.

¿Cómo funciona FluentViewModel? (a grosso modo)

Creo que la mejor forma de explicar cómo funciona, es con un ejemplo: Sigue leyendo