Around the time that Nokia Python was released, someone mentioned that it would be very interestig to see a replacement for the built in Nokia Notepad program. The Notepad program has many limitations: you can’t fit much text on a screen, there’s no easy way to browse or link notes you’ve written, all the typical limitations that you see when writing in a small paper notepad.

It was discussed that a small, wiki-like implementation might be a way to improve the usability of the notepad. Allow people to link between pages or nodes, let them type what they want and link it together. This would greatly improve the usability of having a phone along with you: if you can take notes on it that you can actually usee, there’s less chance you’ll lose them than paper, and you’re far more likely to be able to use something that’s connected than just write one note to yourself.

For a while, I didn’t develop anything on the phone, mostly due to technical issues related to my development process. However, after the recent Python SIG meeting, I decided that the next time I saw people, I wanted the phone to do something useful. So, I took on the challenge: a wiki-like scratchpad.

I started last night, and didn’t get too far before I ran into some symbian related problems: I couldn’t get anydbm to save anything. The file would open, it would stay open, but it wouldn’t sync, and it wouldn’t close. This morning, I finally looked at some code, and realized – wait. I need a full path. And once I got that far, things started looking up. In the hour I had this morning before work, I hacked out the basics: open a node, write to it, save, exit. Paavo on #mobitopia pointed out some other issues: the exit key handler, for one.

Then, over lunch, I created a webpage, and fleshed it out a bit more: adding a feature such that when you hit the action button, the word underneath the cursor is opened as a new node. This was about another two hours of work, spread over lunch and 10 minute breaks from work throughout the day. This included writing a program that catches keypresses and displays their associated keycodes, including learning a bit more about lambdas than I used to. I then had a working wikipad, and have since been adding minor cleanup tweaks.

In the past hour, I’ve created a beta, which allows uploading the wiki database to a webpage as POST data, from which it can be done with what you wish. (I’m currently storing the data in print_r() form, just for the sake of doing so.) From here, it’s pretty easy to imagine how this could allow reimporting the data.

So, the next step is, of course, making this work in a collaborative sense: allowing multiple people to edit one wiki via their phones. However, for the time being, it’s a great little scratchpad app, that’s only likely to get greater. You can get the code from the WikiPad Homepage.

10 Responses to “wikipad”

  1. Dino Says:

    Rumour has it that the Nokia Python docs tell how you can package this as a .sys, saving us lazy blog readers the trouble of copying, pasting, and moving files around on the phone to make it work.

    Something to spend another lunch break on.

  2. mark Says:

    off topic here but any chance of creating another foxtrot rss feed on livejournal?

  3. Christopher Schmidt Says:


    Feel free! Let me know when it’s done.

  4. Christopher Schmidt Says:


    py2sis allows you to convert a Python script to a .sis file: but what’s the point? The only difference between installing a .sis and installing a python script is that you have to go through more hoops to install a .sis file (skipping unsigned software warnings and the like). You don’t have to move files around: just send the .py to your phone, and then it shows up in the Python menu (which you need to have installed anyway).

    What does me converting it to a .sis help with?

  5. Mark Says:

    sorry, maybe you misunderstood me..the foxtrot ( no longer exists and I am unable to create new syndicated feeds, I was hoping you could create another account or any advice which could be helpful..thanks

  6. Christopher Schmidt Says:


    No, you misunderstood me. I know full well that the Foxtrot feed was suspended for copyright violation, and I’m not going to risk my neck in creating something that pisses off people with big, expensive lawyers and large legal funds to sue my pants off. Once was enough.

    However, if you’re interested, you can feel free to do so yourself.

  7. Jessica Allan Says:

    :snerk: Why do they think that you’re going to write more screenscrapers for them? You’re a geek. It’s a toy. You got bored. You moved on. And I have yet to see a single one of them offer you a dime for your trouble. 😛

  8. Mark Eichin Says:

    Very nice – what’s particularly attractive about apps like this is how little code they actually take to get off the ground, and to pass around and change… if I wanted to add a calculation button, I could just do something as simple as add some lines to the end of Application.callback_key that, hmm, looked for an = near get_pos, eval’ed the text to the left of it, and stuffed it in on the right (bracketed by something for replacement). Probably 5 more lines of code total, and it’s a Smarter scratchpad…

  9. Mark Eichin Says:

    22 lines and not 5. And it does collide with numbers (in the rhs) being valid WikiWords; having callback_key call getexpr *first* would solve that the easy way. (I haven’t tried it, but I think if you wanted trig support, for example, just doing “from math import *” at the top of would do it…

    *** 2005/02/21 07:22:02 1.1
    --- 2005/02/21 07:46:23
    *** 12,17 ****
    --- 12,23 ----
    r_endword = re.compile(r'[A-Za-z0-9]+$')
    r_startword = re.compile(r'^[A-Za-z0-9]+')

    + # expressions are
    + # =foo+bar=result=
    + # the result gets replaced
    + r_expr_left = re.compile(r'[^\n\r=]+=$')
    + r_expr_right = re.compile(r'[^\n\r=]+=')
    class Application:
    def getword(self, input, pos):
    """From Sean B. Palmer,"""
    *** 21,26 ****
    --- 27,50 ----
    except AttributeError: sword = ''
    if not (eword or sword): return None
    return eword + sword
    + def getexpr(self, input, pos):
    + try: lhs =[:pos]).group(0)
    + except AttributeError: lhs = ''
    + try: rhs = r_expr_right.match(input[pos:]).group(0)
    + except AttributeError: rhs = ''
    + if not (lhs or rhs): return None
    + return (lhs, rhs)
    + def calc_expr(self, sides):
    + lhs, rhs = sides
    + try:
    + res = eval(lhs[:-1])
    + except Exception, e:
    + res = str(e) + "< %s>" % lhs[:-1]
    + old = lhs+rhs
    + new = lhs+str(res)+"="
    + buf =
    + buf = buf.replace(old, new)
    def upload(self):
    import urllib
    d = {}
    *** 83,88 ****
    --- 107,115 ----
    def callback_key(self):
    i = self.getword(,
    if i: self.open_page(i)
    + else:
    + i = self.getexpr(,
    + if i: self.calc_expr(i)
    def callback_exit(self):
    """Cleanup after ourselves."""

  10. Christopher Schmidt Says:

    Since Mark’s version got totally screwed by the Markdown or whatever filtering is on this weblog, I’ve copied the code of his patch to a seperate file, which you can read more easily. Very cool stuff, glad you’re enjoying the application, and that it allows you to do cool stuff like this.

    Python is great, aint it?