Friday, December 30, 2011

In Vino JQuery, not a Socratic, dialogs

I spent a bit of today adding the capability to Veratas to collect user input in the form of a "dialog". I put "dialog" in quotes, because I used a JQuery dialog within the HTML, rather than a Gtk dialog window.

Before settling on JQuery for this project, I looked at it and YUI in some depth. I was attracted to YUI because it seems very very complete. In fact, it has a filterable and sortable data grid, which is very important to me, as most applications, when you get down to it, are really just CRUD apps.

However, I went with JQuery for Veritas because the samples and tutorials made it seem very easy to get things done, and Veritas has simple needs.

JQuery has a cool page where you can create just the javascript that you need, as well as a theme generator. Note the "grapey" dialog bar in the screenshot, I set that color in the theme generator.

What the Dialog Does
First thing was to lay out the dialog in the normal HTML way. Note that I set it to be display:none, by default.

  <div id="dialog" title="Enter New Bottle" style="display:none;width=00px">
<fieldset>
<p>
<label for="country">Country</label>
<input type="text" name="country" id="country" value="" placeholder="">
</p>
<p>
<label for="region">Region</label>
<input type="text" name="region" id="region" value="" placeholder="">
</p>
<p>
<label for="domain">Domain</label>
<input type="text" name="domain" id="domain" value="" placeholder="">
</p>
<p>
<label for="grapes">Grape(s)</label>
<input type="text" name="grapes" id="grapes" value="" placeholder="">
</p>
<p>
<label for="price">Price</label>
<input type="number" name="price" id="price" value="" placeholder="$">
</p>
<p>
<label for="rating">Rating</label>
<select name="rating" id="rating" value="" placeholder="">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</p>
<p>
<label for="taste">Taste</label>
<input type="text" name="taste" id="taste" value="" placeholder="">
</p>
<p>
<label for="image">Label Picture</label>
<input type="text" name="image" id="image" value="" placeholder="">
<button id="preview_button">Preview</button>
<img id="preview_image" src=""/>
</p>
<p>
<button id="submit_new">OK</button>
</P>
</fieldset>
</div>

Then, I created a "New" button, and wired it up to some code that I was able to get from the excellent JQuery demo pages to display the dialog. Note that the documentation made it really easy to copy and paste my way to success here, including figuring out how to choose different reveal effects and such.

        $( "#dialog" ).dialog({
autoOpen: false,
width: 600,
show: "blind",
hide: "blind"
});
$( "#new_button" ).click(function() {
$( "#dialog" ).dialog( "open" );
return false;
});
The dialog includes a submit button. I wired this up to create a JSON object and send a signal with all this data to the backend using the "send_message" javascript function.
        $( "#submit_new" ).click(function() {
bottle = {"country": + $( "#country" ).val(),
"region": $( "#region" ).val(),
"domain": $( "#domain" ).val(),
"grapes": $( "#grapes" ).val(),
"price": $( "#price" ).val(),
"rating": $( "#rating" ).val(),
"taste": $( "#taste" ).val(),
"image": $( "#image" ).val()};
send_message("new_wine", bottle);
$( "#dialog" ).dialog( "close" );
return false;
});

Yesterday, send_signal took 2 strings: the name of the signal and some other data. Today I changed it to take the name of the signal, and any javascript object. The function uses a popular JSON parcer to stringify the javascript object before using the "set title hack" to pass the data tot he back end.
function send_message(signal_name, data)
{
title = document.getElementsByTagName("title")[0];
message = {"signal": signal_name,"data":data};
title.innerHTML = JSON.stringify(message);
}
Now that I have written that part, I don't have to worry about formatting my data, I can just pass it over.

Similarly, on the back end, I made the HTMLWindow class decode the json and pass it along:

def _on_html_message(self, view, frame, title):
if title != "null":
try:
message = json.loads(title)
except Exception, inst:
print inst
message = {"signal":"error","data":"signal not parsed"}
else:
message = None
self.on_html_message(message["signal"],message["data"])

def on_html_message(self,message):
pass

As a result, subclasses like VeritasWidnow can just use the data without worrying about the implementation. It doesn't do anything with the data yet.

2 Way Communication
I did add one bit of round tripping. It turns out that as a security precaution, the "file" input type does not let the javascript see the full path selected, it only allows the selected file to be uploaded to the server. I hope that I can figure out how to let the user grant Veritas permissions to pass the selected file to the javascript, but I can hack around it if it doesn't turn out to be easy or possible.

Meantime, I let the user type in a full path to the file, and then click "Preview". This takes the entered string, and sends it to the back end.

$( "#preview_button" ).click(function() {
send_message("image_preview", $( "#image" ).val() );
return false;
});


The back end then uses the awesome PIL libary to make a thumbnail, and then passes the path of the thumbnail back. I actully suspect that I will be able to skip the step of saving the file and just use the string data, possible with the Canvas element.


def on_html_message(self, signal_name, data):
if signal_name == "image_preview":
try:
img = Image.open(data)
img.thumbnail((128,128), Image.ANTIALIAS)
path = """/home/rick/.tmp/thumbnail.jpg"""
img.save(path,"JPEG")
path = "file://" + path
self.view.execute_script("receive_signal('set_preview','" + path + "');")
except Exception, inst:
print inst.message
self.view.execute_script("""receive_signal('set_preview_error','Could not find a valid image at %s');""" % data)
Debugging HTML/javascript
Another handy think I found today is that I can load the HTML page into Firefox, and use a web console to poke at it. Very handy. Of course, this works now because I am not doing string replacement, but I think that I can actually make a similar thing work with a WebKit window.

Next
So now that I can collect the info from the user, I'll start saving the data in a sqlite database, and then work on presenting the data to the user.

Thursday, December 29, 2011

In Vino Veritas and HTML5 Client Apps


So, basically, not to put to fine a point on it, I've started to write apps for Ubuntu in a different way, essentially, replacing Gtk (or really PyGtk) with HTML5. This is my first post about how am I doing it. I've just started a project called "Veritas" which will be a wine tasting database for my wife and I. We'll be able to enter information about each bottle that we drink, and then look at trends over time, perhaps helping us pick nicer and nicer bottles as we go.

First, though, what happened, I thought you got along great with Gtk?
Well, I do still have a soft spot in my heart for pygtk. Believe me, I've written plenty of code in it. I know the ins and outs pretty well, and I'm able to do things with it like write a response UI that doesn't block to much during run longing processes and such. PyGtk is great for building "boxy" apps, but I think a lot of people want to build slicker apps than Gtk is really designed for, or at least design them in different ways thatn Gtk supports well.

Why not Qt and QML?
This app, in fact, would be well suited for a QML app. However, I have other apps in mind, and I found QML/Qt to not be quite up to the job. For instance, I want to write a communication app to combine OpenLDAP and IRC functionality. Currently, there are no Qt libraries for LDAP or IRC, so to write such an app with QML, I'd have to write C++ Qt code to wrap whatever C libraries, and then write code to export models from that C++ code to expose it the right way in QML. That is a lot of overhead, especially considering that there are good Python libraries for LDAP, IRC, and pretty much anything desired. So, I designed myself a system that let me stick with Python for the back end code.

Also, QML lacks a widget toolkit at the moment, so there would be a lot of manual coding of things like buttons and such.

Why HTML5?
I chose HTML 5 for the widget toolkit for a few reasons.
  • I already know HTML/CSS/Javascript pretty well, and I know that cool things can be done with it. I bet a lot you all know it pretty well too.
  • Webkit is very well supported Open Source used and maintained by many large companies.
  • There are lots of cool widget toolkits to choose from, I'm currently looking at YUI since I think it's in pretty heavy use by some of the web teams at Canonical.
  • Because I wanted to try out HTML for client programming.
My Application Architecture
First, I laid everything out total flat to start with. This is because I wanted to come to grips with making the view code talk to the model/controller code without mucking with any extra complexity. Of course, I will need to modify the layout as the actual code grows.

Currently, I am only focused on makinga client application programming system, though I may, in the future, extend the system so the model/controller back end could be on a server, and the view available via a browser. But this is firmly out of scope right now. I am, however, trying to be cognizant of making the system essentially portable by sequestering the Gtk specific code into specific files that can be replaced if I want to run it without Gtk at some point.

Therefore, there are some important differences to note if you are used to web programming.
  • The back and and view code communicate via signals to each other. This is much different than web programming, where the view makes a request and waits for the server to respond with a string (for Ajax apps) or redirects to another view passing some state along with it.
  • This means that the back end can send signals to the view. The view does not need to pole to see if the back end is ready, for example, the back end can just send a signal when it is.
  • This also means that long running processes can block the GUI, since they are running in the same thread. I shall most likely put the Gtk main loop in it's own thread so I can run run-longing processes in seperate threads, and then communicate between them.
  • The view cannot call a function on the back end, and wait for a response (for example with XmlHttpRequest). Rather it can only send the back end a signal.
  • The back end is not stateless. This is greatly simplifying. Most web programming frameworks have a lot of code to maintain state by storing it and accessing it on future requests by reading cookies stored on the client.
  • Currently, I have nothing like server side tags that are the bread and butter of most web programming frameworks. This typically works via string replacement, so I could either find a library to add this functionality, or make it easier to do string replacement with the HTML. This is typically desirable for a web app since you want to configure the HTML before it is sent from the server. Less important in a client app, but still, some string replacement of HTML may save some effort in writing complex javascript against the browser DOM.
Ok, let's get to the good stuff. To bin file is called "veritas". Running this file creates a VeritasWindow and then starts the Gtk main loop. The Gtk main loop is there because the Webkit window has to run inside something, and I chose a Gtk Window for this because of the simple integration with Ubuntu.

A VeritasWindow only does 2 things so far. It tells it's baseclass "HTMLWindow" what html file to load, and it listens for signals from that view. Later, it will create new HTML5 Windows and do other stuff in response to signals from the HTML view.

HTMLWindow is meant to be used only as a base class. First, it creates a top level menu so you can quit the app, and also, I think that apps should have menus (I haven't really thought through how menus will work in this system yet, but I'm hoping that DBUS Menu helps me out). Then it loads the HTML that the subclass told it to load. It also listens for signals from the view, parses the signals and has what is essentially a virtual function called "on_html_message" for subclasses to override. You should be able to receive messages from the view without looking at the internals of how it works. Among other things, this is platform specific.

main.html is the HTML5 code for the main window. All it does now is send a signal that it is loaded, and you can see that I added a heading. When paired with main.css the layout and look and feel of the UI will be controlled completely in the view code.

helpers.js is a file that I think I may need to handle platform specific signals sent to the view. Of course, you can always call "execute_script" and send whatever you want from the backend, but I think it's cleaner to expect well formatted signals from the back end instead.

Conclusion
So, that's basically all the boiler plate for making an HTML5 client app for Ubuntu. This represents a few hours of work on my part to make a re-usable and extensible system.
My next steps will be to do some database programming with sqlite, then I'll probably build a data input window for it. This certainly calls to mind Rails-like thinking (hmmm, I have the model, why can't I generate the view from that on the fly?), but, I don't think I want anything that complex. After I finish Veritas, I'll then extract the base classes and such, and perhaps create a Quickly template, then go ahead and work on my certain to be more complex communication application.