QtRuby on Windows (Qt 4.6.1 and Ruby 1.8.7)

I've been wanting to learn how one binds a GUI Toolkit into Ruby for quite a bit, I've now finally acted upon it. I first investigated possibilities by looking into this list. Shoes seemed like a nice fit :) yet it lacked the punch I was gunning for -- also, being a fan of drag and drop Widget arrangement and auto code-generation, it was obviously a tad under-par. Seeing as my first intership a bit back entailed developing a small GUI in Qt (and liking it !), I wanted to reembark on the Qt ship.

It's indeed a cute GUI framework, very well documented (books available as well), free and open-source. It's also powerful and feature-packed, gaining interest since its launch and being used in many projects (last.fm Scrobbler, Google Earth, VirtualBox, KDE and so on -- just do a search for 'Qt*.dll' on your HDD and see :) ) with its core being developed by Nokia. 

Having passed the introduction (yay!), I'd like to share a non-painful way of installing Qt bindings for Ruby (QtRuby) on Windows (tested on Windows 7 Professional x64, I guess the method should work on XP as well).

I downloaded the Qt SDK 1.1 at first, that seemed to be a bit overkill, Maemo emulator and what not. To get started, download the latest version of the Qt libraries (here is a direct link to download v4.7.3). Also grab a version of MinGW with gcc 4.4 (direct link here), since the new installer doesn't provide a download link, only requesting the install folder for MinGW and complaining if it's not a good version :).

I followed a nice article on what needs to be installed next: a custom-brewed installer for Windows, of course! Always a pleasure to have to monkeypatch something to make it play well with ole' Win32. Download via direct link and install. Choose not to include the Qt folder into the PATH, that will interfere with what we're gonna (monkeypatch) in the next step. Also provide the path to your Ruby's bin folder (tested with Ruby 1.8.7 p330, e.g. the last patch for the 1.8.x version -- as the title states, the current version of the QtRuby library which makes all the magic of connecting Qt to the Ruby world does not support Ruby 1.9.x).

Now it's time to get the aforementioned QtRuby library, use the direct link . It's also available as gem form, I guess it should also work when installed via rubygems, I've chosen to do a manual install. Having downloaded the QtRuby gem for Win32 (latest version: 2.1.0), run a 'gem unpack' on the qtruby4-2.1.0-x86-mswin32.gem file.

Then navigate to the newly created folder (qtruby4-2.1.0-x86-mswin32) and open the bin sub-folder (you can optionally open the lib folder in a new Explorer window as well, using CTRL+ENTER. Keep it minimized, will be used in the next step). Select the following .dll files (sort by file type beforehand), basically from Qt3Support4.dll until the end of the folder's files :

Gem-bin

Place the selected files into the clipboard (CTRL+C). Then navigate to your Ruby installation folder's bin sub-folder (within the VM in which I tested this process, the path was C:\ruby-1.8.7-p330-i386-mswin32\bin) and paste. All 37 files are now located in your Ruby's bin folder, awaiting to be found and used by QtRuby. Don't close the Explorer window, minimize it as we'll return here in the next step.

Only one step remains until you can test your installation. Go to the unpacked gem folder (I extracted it to the Desktop for easy access, it was under the C:\Users\Dr1Ku\Desktop\qt\qtruby4-2.1.0-x86-mswin32 path in the VM) and open the lib sub-folder (or maximize the already opened Explorer window). Simply select all files (CTRL+A) and copy them (CTRL+C) into the clipboard as well. Then go to the lib sub-folder of your Ruby installation folder (or up a few folders if the window is still open) and navigate to the following path: [RUBY_DIR]\lib\ruby\site_ruby\1.8 (usual location is C:\ruby-1.8.7-p330-i386-mswin32\lib\ruby\site_ruby\1.8) -- It's a bit of a twisty path indeed. Paste the files. You're good to go!

Open a shell (a 'command prompt', or cmd) and type in irb. Then write require 'qt4'. It should return true, e.g. the QtRuby library was successfully loaded. Now you can write the following test lines to see that QtRuby is working :

a = Qt::Application.new(ARGV)
b = Qt::PushButton.new("abc")
c.resize(100,30)
c.show
a.exec

Now you can also test that Qt 4.6.1 was indeed installed, I chose the FileSystemBrowser Class since it's first been introduced in Qt 4.4 (e.g. a newer version than 4.3.4, the version recommended by the QtRuby installer for Windows mentioned earlier. It works, as you can see below. I also tried including a new Qt 4.7 class , that obviously backfired. An example of the way in which Ruby 1.9 fails to play well with QtRuby 2.1.0 is also included below:

(download)

I tried to run QtRuby on Ruby 1.9.2 as well, yet as pointed out in another article, this is a pipe dream, since QtRuby only works for Ruby 1.8.x. Another caveat is that upgrading the Qt version you're using to compile your Qt/Ruby code does not work, since QtRuby uses the Qt 4.6.1 DLLs as of version 2.1.0. Still, it's better than running Qt 4.3 !

Right, so that would be the conclusion to this small walkthrough, I hope someone will find it useful. Happy hacking !

Don't forget to check this space for an automated way of integrating the sweet Qt Designer into your Qt + Ruby workflow ;), the small script is ready, it must be polished a bit before it hits the limelight. Thanks for reading !

Here's a list of further resources I recommend, related to QtRuby and Qt in general :

AndroidGeoFixTelnet

After receiving a ping earlier today via my Google Profile I remembered I did not post this tiny bit of code I wrote last semester.

We were doing some small Android development which involved running some location mocks. The way to do it via the Android Emulator is to issue  a geo fix lng lat command via telnet. As you can see, it's (lng, lat) and not (lat, lng) as usual. I remember this was a big gotcha in the first few hours of testing the solution out.

Another big caveat is the fact that the lng, lat pairs are not parsed to their full precision and are apparently truncated to one decimal place – e.g. 8.57139 is interpreted as 8.5 . This makes the telnet solution rather impractical, there are some fixes available apparently.

I've just cleaned up some code I wrote in Ruby to issue multiple such geo fix commands and it should work. It's a small command-line tool, check out the source code on Github, link below. 

License : Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

Source Code : Full-disclosure source-code is on GitHub.

Side note : You can also use a mock / test LocationProvider, reach out if you need the code I've used. As with this telnet-based approach, it has its caveats. Mainly crushing your 'normal' GPS Provider and you having to restart Android every time you wish to get rid of the said MockLocationProvider :)

 

GMail Multiple Inboxes - quick tip

I've been using the fabulous Multiple Inboxes Lab for GMail ever since it was created by one of my favourite programming superheros, Vivi . Here's my setup :

  • 2 panes, 25 items each, right side
  • Pane 1 : Search query = "{is:starred} & -{in:inbox | in:trash}", name = "Seemingly once important". Basically all starred + archived conversations (alternate name = "Fallen stars" ^_^).
  • Pane 2 : Search query = "-{in:inbox & in:trash & is:starred & label:Drafts}", name = "Apparently everything else" . Basically a small "All Mail" pane.

I've recently discovered these correct queries fiddling around with the GMailFilterCompactor , my previous queries did not yield satisfactory results.

Enjoy !

GMailFilterCompactor

Although officially on vacation, I used a bit of spare time to create a allegedly useful bookmarklet thingie, dubbed "GMailFilterCompactor" :)

Purpose : Say you have a lot of filters set up in GMail which serve the same functionality, e.g. Label as "Stuff". It would be swell if you would have written them in a single filter, so that a change (a re-labeling, a 'mark as read' or a 'mark as important') would only have to be made once and automagically propagate within every filter.

I didn't take this maintainability perspective into account as I have created filters throughout the years, thus ending up with some 100 "Newsletter" filters (hey, promotions, right ? :) ) !

Today I wanted to also add a "Never mark as important" option to those filters -- that wish turned into an obvious no-go, since there's no functionality for compacting the filters, it's a real out-of-band request. Therefore I built one :)

The visual variant of the "purpose" :

Purpose

One-click usage : (work in progress) Drag this Bookmarklet onto your Bookmarks Toolbar. Open up your GMail, choose Settings (cog symbol) >> Mail Settings >> Filters. Click the dragged bookmarklet, wait a bit.. tada !

More-clicks usage : Download the minified version from GitHub, copy it into your trusty clipboard, open up a Developer Console (Firebug symbol or 'Inspect Element' anywhere in Chrome, then click on the 'Console' tab). Paste the code, hit enter. Follow the quick and simple instructions (don't worry, GMail asks for a confirmation again if you accidentally clicked the 'OK' button for the deletion part !) and there you go, all done.

Usage notes : The current / initial version works if you're willing to get your hands dirty (e.g. copy the source code into a Console / Firebug). I'm trying to build a bookmarklet, I'm a bit skeptical about the end-outcome, we'll just see. NOTE : In Chrome / Safari, the script doesn't work since the jQuery injection is (obviously) considered trublesome. I'll think of some hacks in the meantime :)

'Testimonial' : With the first pass, I went from 107 filters to 6 compacted filters. Along with some improvements for multi-passes, I now have only 3 compacted 'Newsletter' filters.

License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License (mainly Non-Commercial since it could render some havoc within a Google Apps context, I guess :) ).

Source Code : Full-disclosure source-code is on GitHub.

 

Enjoy !

P.S. : I will also devise a small script to handle a simple management of such 'compacted' GMail filters (as outputted by this tool), stay tuned.