Archive for October, 2008

Dieting Again

Tuesday, October 28th, 2008

I’ll be dieting for two months starting November 1st. Everything is planned out and ready. I am mentally prepared as well. You know, being underslept, undernutritioned and tired, all at the same time is demanding. I can’t say it is much fun, but I don’t really dread it. I have gained 4 kgs since the last diet. I already look like a fat pig to myself. So it is just time for another.

I frequently hear “why do go through all this, it is really unnecessary”. Why do people say that? I find it really annoying. What could be more natural for someone to take care of one’s pysical existance? You do brush your teeth right? How is staying fit different or less important than that? Let us hang 15 kgs of fat around your waist and you live with it just for a week. And see if your opinion changes.

Bookmark and Share

Getting A Little Further Than Hello World With Qooxdoo

Friday, October 17th, 2008

I have mentioned about Rich Internet Applications in a previous post. Qooxdoo is an AJAX framework, especially strong on creating desktop-like GUI’s. It allows you to build your interface in an object oriented manner. Like tkinter or GTK, and much more than the others it is like swing.

Qooxdoo is well documented and has a clean API. It comes with a Python program to help with builds. Because it is such a big framework you test on a partially compiled source and when finished this build program generates a single (actually two, it also generates a loader), compact (and somewhat obfuscated) file for performance. I strongly advise you to give it a try. The following is a small introductory tutorial. It aims to go little further than Hello World. This is not a tutorial explaining object oriented programming concepts, I assume you are already fluent in OOP.

Create The Skeleton

Screenshot of finished application

Screenshot of finished application

We’ll create a simple calculator-like application. I am assuming you have downloaded (latest version is 0.8 for today) and extracted the source into a directory. Let’s call it qxtut. The first thing we will do is to create a skeleton of our application with the following command;

./qooxdoo-0.8-sdk/tool/bin/create-application.py --name basicmath

This command has created the following directory structure under ./basicmath;

qxtut/
  qooxdoo-0.8-sdk/
  basicmath/
    source/
    build/
    cache/
    api/
    config.json
    Manifest.json

Well, some of the directories (build & cache) are not there yet. But as we go on they will appear, I just wanted you to see how the application is organized. config.json and Manifest.json files are configuration files for the build tool. We don’t need to change them for this tutorial, but you are welcome to check their contents.

Let us build our source for the first time;

cd basicmath
./generate.py source

Now if you open ./source/index.html in your browser you can see a Hello World application in action. We’ll replace this with our own program. But before we proceed I’d like to point out a few things;

  • When we define our classes, we call a class method define on qx.Class and pass our class’ name (along with its namespace) and its contents as arguments. We don’t define our classes using prototypes, in order to take advantage of Qooxdoo’s object oriented programming features.
  • Qooxdoo supports single inheritance (with mixins). We define our base class, if we have one, using extend key.
  • Instance members are defined inside the members key and class members are defined inside the statics key.
  • construct and destruct are two special functions for initialization and cleanup of the class.
  • Qooxdoo supports [properties](http://en.wikipedia.org/wiki/Property_(programming)) as well, but it is outside of this tutorial’s scope.
  • Finally, “#asset(basicmath/*)” line tells the build program to include assets (images etc) in qxtut/basicmath/source/resource/basicmath directory.

Custom Classes

Let’s start building our application now. Here is a compact version of Application.js;

/* ************************************************************************
#asset(basicmath/*)
************************************************************************ */

qx.Class.define("basicmath.Application", {
    extend: qx.application.Standalone,
    members: {
        main: function()
        {
            this.base(arguments);
            if (qx.core.Variant.isSet("qx.debug", "on")) {
                qx.log.appender.Native;
                qx.log.appender.Console;
            }
            // Our code will come here
        }
    }
});

Now we will create a custom class named Operation. This class will take two operands and perform an operation on them, and then later we will add it the ability to report the result of the operation. Paste this as Operation.js;

/* ************************************************************************
#asset(basicmath/*)
************************************************************************ */

qx.Class.define("basicmath.Operation", {
    extend: qx.ui.container.Composite,
    construct: function() {
        this.base(arguments);
        var layout = new qx.ui.layout.HBox(6);
        this.setLayout(layout);
        this.operand1 = new qx.ui.form.TextField("0");
        this.operator = new qx.ui.form.SelectBox();
        this.operator.add(new qx.ui.form.ListItem("add"));
        this.operator.add(new qx.ui.form.ListItem("subtract"));
        this.operator.add(new qx.ui.form.ListItem("multiply"));
        this.operator.add(new qx.ui.form.ListItem("divide"));
        this.operand2 = new qx.ui.form.TextField("0");
        this.result = new qx.ui.basic.Label("0");
        this.add(this.operand1);
        this.add(this.operator);
        this.add(this.operand2);
        this.add(this.result);
    },
    members: {
        operand1: null,
        operator: null,
        operand2: null,
        result: null
    }
});

The code should be self explanatory. Notice here, we define operand1, operator, operand2 and result as members of the class. Also notice we initialize those members in the constructor and not in the class body1. This is because their respected values (classes) are derived from the non-primitive Object type. Therefore if we have assigned them a non-primitive type (such as the array [1, 2, 3]) in the members section; all instances would point to the same object.

Let us now plug this object in our application. Replace the comment line “// Our code will come here” with the following;

this.getRoot().add(new basicmath.Operation);

Now, when we compile the source and run index.html we should see our widgets in place.

Screenshot of an Operation widget we have just created

Screenshot of an Operation widget we have just created

Simple Behaviour

We want our widget to calculate the operation and show us the result. Let’s update the members section of Operation with the following;

members: {
    operand1: null,
    operator: null,
    operand2: null,
    result: null,
    updateResult: function() {
        var v1 = this.cleanField(this.operand1);
        var v2 = this.cleanField(this.operand2);
        var r;
        switch(this.operator.getValue()) {
            case "add": r = v1+v2; break;
            case "subtract": r = v1-v2; break;
            case "multiply": r = v1*v2; break;
            case "divide": r = v1/v2; break;
        }
        this.result.setContent(String(r));
        this.operand1.setValue(String(v1));
        this.operand2.setValue(String(v2));
    },
    cleanField: function(field) {
        var val = parseInt(field.getValue());
        return isNaN(val) ? 0 : val;
    }
}

We have added two functions here updateResult and cleanField. Now we make use of them, change the construct with the following;

construct: function() {
    this.base(arguments);
    var layout = new qx.ui.layout.HBox(6);
    this.setLayout(layout);
    this.operand1 = new qx.ui.form.TextField("0");
    this.operand1.addListener("input", this.updateResult, this);
    this.operator = new qx.ui.form.SelectBox();
    this.operator.add(new qx.ui.form.ListItem("add"));
    this.operator.add(new qx.ui.form.ListItem("subtract"));
    this.operator.add(new qx.ui.form.ListItem("multiply"));
    this.operator.add(new qx.ui.form.ListItem("divide"));
    this.operator.addListener("changeValue", this.updateResult, this);
    this.operand2 = new qx.ui.form.TextField("0");
    this.operand2.addListener("input", this.updateResult, this);
    this.result = new qx.ui.basic.Label("0");
    this.add(this.operand1);
    this.add(this.operator);
    this.add(this.operand2);
    this.add(this.result);
}

We just added these three listeners to update the result when an operand or the operator changes;

this.operand1.addListener("input", this.updateResult, this);
this.operator.addListener("changeValue", this.updateResult, this);
this.operand2.addListener("input", this.updateResult, this);

The last parameter (this) for addListener (even though it is sometimes unnecessary) set the scope within the listener code (the second parameter). Qooxdoo handles most of the binding automatically, I think this is included for flexibility.

Let’s compile and run again. The result of the operation should update as you change the values now.

Events To Tie All Together

I’ll give you the finished code first and then we can go over the details. Here is Operation.js;

/* ************************************************************************
#asset(basicmath/*)
#asset(qx/icon/Oxygen/*)
************************************************************************ */

qx.Class.define("basicmath.Operation", {
    extend: qx.ui.container.Composite,
    construct: function() {
        this.base(arguments);
        var layout = new qx.ui.layout.HBox(6);
        this.setLayout(layout);
        this.operand1 = new qx.ui.form.TextField("0");
        this.operand1.addListener("input", this.updateResult, this);
        this.operator = new qx.ui.form.SelectBox();
        this.operator.add(new qx.ui.form.ListItem("add"));
        this.operator.add(new qx.ui.form.ListItem("subtract"));
        this.operator.add(new qx.ui.form.ListItem("multiply"));
        this.operator.add(new qx.ui.form.ListItem("divide"));
        this.operator.addListener("changeValue", this.updateResult, this);
        this.operand2 = new qx.ui.form.TextField("0");
        this.operand2.addListener("input", this.updateResult, this);
        this.result = new qx.ui.form.TextField("0");
        this.result.setReadOnly(true);
        var close_button = new qx.ui.form.Button(
            null,
            "qx/icon/Oxygen/16/actions/application-exit.png"
        );
        close_button.addListener("execute", function(e) {
            this.fireDataEvent(
                "changeResult",
                0,
                parseFloat(this.result.getValue()),
                false
            );
            this.destroy();
        }, this);
        this.add(this.operand1);
        this.add(this.operator);
        this.add(this.operand2);
        this.add(new qx.ui.basic.Label("="));
        this.add(this.result);
        this.add(new qx.ui.core.Spacer(8));
        this.add(close_button);
    },
    events: {
        "changeResult": "qx.event.type.Data"
    },
    members: {
        operand1: null,
        operator: null,
        operand2: null,
        result: null,
        updateResult: function() {
            var v1 = this.cleanField(this.operand1);
            var v2 = this.cleanField(this.operand2);
            var r;
            switch(this.operator.getValue()) {
                case "add": r = v1+v2; break;
                case "subtract": r = v1-v2; break;
                case "multiply": r = v1*v2; break;
                case "divide": r = v1/v2; break;
            }
            this.fireDataEvent("changeResult",
                r,
                parseFloat(this.result.getValue()),
                false
            );
            this.result.setValue(String(r));
            this.operand1.setValue(String(v1));
            this.operand2.setValue(String(v2));
        },
        cleanField: function(field) {
            var val = parseInt(field.getValue());
            return isNaN(val) ? 0 : val;
        }
    }
});

And Application.js;

/* ************************************************************************
#asset(basicmath/*)
#asset(qx/icon/Oxygen/*)
************************************************************************ */

qx.Class.define("basicmath.Application", {
    extend : qx.application.Standalone,
    members : {
        main : function()
        {
            this.base(arguments);
            if (qx.core.Variant.isSet("qx.debug", "on")) {
                qx.log.appender.Native;
                qx.log.appender.Console;
            }
            var layout = new qx.ui.container.Composite(
                new qx.ui.layout.VBox(8)
            );
            var layout_footer = new qx.ui.container.Composite(
                new qx.ui.layout.HBox(6)
            );
            var total = new qx.ui.basic.Label("0");
            var add_button = new qx.ui.form.Button(
                "Add New",
                "qx/icon/Oxygen/16/actions/list-add.png"
            );
            add_button.addListener("execute", function(e) {
                var new_operation = new basicmath.Operation();
                layout.addBefore(new_operation, layout_footer);
                new_operation.addListener("changeResult", function(e) {
                    var old_total = parseFloat(total.getContent());
                    var new_total = old_total - e.getOldData() + e.getData();
                    total.setContent(String(new_total));
                }, this);
            }, this);
            layout_footer.add(add_button);
            layout_footer.add(total);
            layout.add(layout_footer);
            add_button.execute();
            this.getRoot().add(layout);
        }
    }
});

Let’s go top-down and begin with the changes in the Application.js;

var layout = new qx.ui.container.Composite(new qx.ui.layout.VBox(8));
this.getRoot().add(layout);

We don’t necessarily need to subclass everytime we need specialized behaviour. Since I had intented to re-use Operation I have it as a seperate class. But for the layout of the application I just instanciated some classes and tweaked them inside Application.main. layout here is the topmost widget, we will put everything else in it. Basically one or more Operation‘s and a footer to dispay the grand total. VBox layout is by the way a layout manager that stacks children vertically, and a HBox stacks horizontally.

var layout = new qx.ui.container.Composite(new qx.ui.layout.VBox(8));
var layout_footer = new qx.ui.container.Composite(new qx.ui.layout.HBox(6));
var total = new qx.ui.basic.Label("0");
var add_button = new qx.ui.form.Button(
    "Add New",
    "qx/icon/Oxygen/16/actions/list-add.png"
);
add_button.addListener("execute", function(e) {
    var new_operation = new basicmath.Operation();
    layout.addBefore(new_operation, layout_footer);
    new_operation.addListener("changeResult", function(e) {
        var old_total = parseFloat(total.getContent());
        var new_total = old_total - e.getOldData() + e.getData();
        total.setContent(String(new_total));
    }, this);
}, this);

We define a label total to hold the grand total of all operations and an add button for new operations. Notice the closures work on 7th line. Although we limit ourselves a little bit to take advantage of OOP, we are still in a dynamic environment. Finally we tie all these components together and finally add the layout to the application root.

add_button.execute();

This instantiates the first Operation for us. We execute the button instead of creating the widget programmatically to avoid the code duplication (see the “execute” listener on the add_button).

Now let’s take a look at the changes in Operation.js. I have replaced the result Label with a TextField (remember to run “generate.py source” each time dependencies change). I wanted to take advantage of the getOldData function on TextField‘s changeValue event. But appereantly it doesn’t supply the old data. But I kept it as a TextField anyway, setting it read-only.

Then I decided that Operation should signal for a result change (maybe this is more politically correct) and added a custom event changeResult on it.

events: {
    "changeResult": "qx.event.type.Data"
}

This event is fired inside Operation.updateResult;

this.fireDataEvent(
    "changeResult",
    r,
    parseFloat(this.result.getValue()),
    false
);

The second parameter is returned from e.getData() and the third is from e.getOldData(). Therefore we can calculate the grand total without iterating all Operations;

var new_total = old_total - e.getOldData() + e.getData();

An important point here is to fire changeResult to correct the grand total before we destroy an Operation;

close_button.addListener("execute", function(e) {
    this.fireDataEvent(
        "changeResult",
        0,
        parseFloat(this.result.getValue()),
        false
    );
    this.destroy();
}, this);

Wrapping Up

Now it should work correctly, if I haven’t made a typo of course. Let us build it with;

./generate.py build

It generates a loader (~150kb) and an application script (~400kb). You don’t need the Qooxdoo source anymore, you can just upload the contents of the build directory and your application would run.

This concludes my a little further than Hello World tutorial. If you find errors or typos, or have any questions please leave a comment here or contact me at muhuk@jabber.org.


1: Here is an explanation in Qooxdoo manual.

Bookmark and Share

My Little Distractions

Thursday, October 16th, 2008

I am not one of hyper-connected people who uses ten different micro-blogging services and maintains their profile in six different social networks and, just for the old times sake, frequents in certain forums. No, I’d rather just finish my work and then if I have time I can read a blog post or two (play). But most of the time I have my IRC client (#fazlamesai @ irc.freenode.net) and Plurk open. For short distractions. I don’t have a very long attention span, and I need short distractions frequently or else I get a headache.

I think RSS is one of the most helpful tools of web. It is easy, efficient and non-distractive. If you choose who you follow well, you would have an endless flow of useful information. I think everyone should use RSS. If you are not already following any feeds, you can start with Fazlamesai (in Turkish) or Slashdot.

First thing IRC reminds me is thousands of people sitting in front of computers asking each other ASL? or doing some other useless small talk. Let me add almost none of those people in this picture knows for sure whether the others are actually who they say they are. And a significant number of them just fake their identity (such as a thirty nine year old guy impersonating a eighteen year old girl). Not a healthy environment. But if you can turn your head from all the fun these chat rooms offer you can find chat rooms, for example, where open source people gather and help each other. Just find and enter your favourite software’s chat room, #python, #firefox, #debian…

I started using Plurk, first becase I was curious about amix‘s startup. Then I decided to stay a little longer to further analyze how they have integrated game elements in their application. Then I kept on Plurking to get to know the people (early adapters) and to witness the evolution of a social network. I still use Plurk almost everyday, because it gives you the feeling that it is working1.

Plurk is a so-called persistent chat application. You can think of it as a cross-breed between instant messaging and e-mail. It is possible to carry on real-time conversations, but when you come back later you can still find (and participate) older discussions. I think you can do this with other micro-blogging applications (such as Twitter), at least with their desktop clients. With Plurk this is possible in the browser.

It is not just AJAX that makes Plurk an attractive service. It has an elegant and feature rich interface. Posts are laid out (horizontally) on a timeline that you can scroll with your mouse. When you click on one of the posts it expands itself down to show you the comments and other details. No page loads. You can also fully customize the interface, change the appereance, hide some elements, add new ones… If you check out Plurk, you will see it is designed to be fun.

I think introducing this fun element is very important. We don’t do micro-blogging because we need to, it doesn’t solve any of our everyday problems. We do it because we want to socialize and have fun. Fun is normally a product of social interaction. But if you can make the interaction itself fun as well, that is so much better. Plurk has badges and a karma system. Basically you earn karma if you plurk frequently and in quality. The more karma you earn the more you quirks you get, such as adding a profile title or unlocking smileys. Now, this may sound silly to you. Why should we care? Well, you might not care, but in general people do care. Playing is the first complex skill we have learned, so we have a natural tendency to play even in adulthood.

There is one last thing I would like to mention. I think this is important too, for a successfull web service. Plurk changes, (naturally) it changes in place, and it changes to conform your usage. One example for that is when I noticed the “US Elections 2008″ tab. It just appeared next to “All Plurks”, “My Plurks”, “Private” tabs one day. That’s a nice thing. But, wait there’s more. The next day an X appeared on the right of that tab. Not being an U.S.A citizen I clicked it and the tab disappeared. Which is also nice. But, wait there’s even more. The next day the elections tab didn’t show up again. Nothing, fancy. Just as one would have expected. But very important. Does many of your everyday services pay special attention to details like this. Users do, at least in a sub-conscious level. It is like having a new piece of clothing and feeling that you have been happily wearing it for years. It just fits.

So, what was I saying? Little distractions. But you need to manage them. You want a short cool off period, not losing focus all together. Plurk is a nice nice service. IRC still has something to offer. RSS is the king for me. But I still have work to do now. Introducing distractions without proper discipline quickly turn into inefficiency.


1: This deserves a post of its own.

Bookmark and Share

Happy Birthday Fazlamesai!

Thursday, October 9th, 2008

Fazlamesai.net, the geek hub of Turkey, is now 8 years old. Happy anniversary, we love you!

Bookmark and Share