It will probably help to see the code I had just before I got it all working, and the code I use today. Both the .js and .ui files can be found at http://www.cricalix.net/~dhill/kjs/. If I make any updates to the working code, the files will be updated (though I doubt I’ll be changing much from here on out).
Step 1: Deciding what I wanted
The general concept was that I wanted a small window with a dropdown list of my online contacts, a small text entry box and a ‘Send’ button. This would be sufficient for my needs, as I usually only have about 5 people on my contact list (work related in this case).
Step 2: Looking up how to do it
If you’ve ever searched for say ‘dcop bash’ on Google, you’ll know that there really isn’t that much that immediately jumps out at you. Throw in the extra keyword of ‘tutorial’ and you might find the IBM DeveloperWorks tutorial (which I didn’t find when I was looking!). However, this isn’t too useful, as bash doesn’t do the whole ’small window with a dropdown list’ thing. Searching for ‘dcop kjs’ is a bit more useful (if you know that KJS is the KDE JavsScript interpreter and supports windows etc), linking primarily to the examples at XMElegance.
Even with the reference examples from XMElegance, I wasn’t too much further along, as they didn’t seem to explain quite what they were doing. weather.js ended up being my starter code, even though it didn’t work. I also read SourceXtreme quite a bit while trying to grasp how to do things.
The other very useful tool for this whole excercise was kdcop – the GUI DCOP explorer for KDE. It gives you a simple interface to browse all of the DCOP aware programs currently running, and even test the APIs.
Listing some of the Kopete interfaces:

Testing the messageContact() interface:

Step 3: Trying
I slowly managed to combine the various examples from XMElegance and SourceXtreme into a coherent looking bit of JavaScript. Looking doesn’t necessarily mean working though. Early versions of the script tried to put together the UI using object calls in the .js file. This sort of works, but it’s not a very elegant or maintainable (to me) way to build a small application – primarily because there was no easy control of element positioning. Bearing this in mind, I installed QT Designer, and dove head first into building myself a nice little dialog.
The dialog method worked, but had a fairly fatal flaw – it wouldn’t obey any of the sizing restrictions I put on it. This meant that the window that popped up was usually smaller than the elements contained within. A bit more research indicated that a dialog wasn’t what I needed – I needed a widget. Once I converted my interface to a widget, the calls to display it worked just fine, and it started up with the dimensions I wanted.
Step 4: Debugging
The initial code ran quite well, other than a few neat bugs. Bug 1 was messing up the KMainWindow::UI::connect() call, and pointing to a non-existant function. This mistake generated a wonderful error that was brilliantly clear.
Uncaught TypeError exception at: -2147483648
Yes. Well. I suppose in the JavaScript paradigm the connect call would be wrapped in a try/catch pairing or similar.
Once I worked out that problem, I found that I could press the Send button, and nothing would happen. kopete->kopeteiface->messagecontact() was returning false, indicating that my parameters weren’t right for whatever reason. At this point, I semi-gave up when even using toString() didn’t work.
Step 5: Debugging redux
The next day, I took another run at the non-working code. At this point, I had a code block that read
var to = toString(win.child('send_to').currentText);
var msg = toString(win.child('send_text').text);
var state = dcop.call("kopete","KopeteIface","messageContact(String,String)", to, msg);
Re-reading the messageContact definition in kdcop, I noticed that the parameters were QString, not String. A quick edit later, I had code that looked like
var to = win.child('send_to').currentText;
var msg = win.child('send_text').text;
var state = dcop.call("kopete","KopeteIface","messageContact(QString,QString)", to, msg);
and all was better in the world. Kopete popped up a chat window, sent the message to the recipient and that was it. The text entry field didn’t clear itself, which was minorly annoying. That was solved with a
win.child('send_text').text = '';
entry right after the dcop.call line.
One thing now remained that wasn’t in the original specification – reloading the contact list. Loading it once at start and then never reloading it doesn’t work very well if someone logs off. Because we use Jabber at work, messages are stored offline, but the UI isn’t behaving in a consistent manner – I can’t message someone who is offline when the script starts, but I can message them after they log off.
Step 6: Tweaking the code
The final tweaks to the code involved adding a reload/refresh button to reset the contact list on request, and a call to the refresh function after sending a message. With a bit of work, the script could be extended to poll the Kopete API every n seconds to see if the list has changed (or just update the list regardless).
The final product:

Comments
Leave a comment Trackback