Monday, April 26, 2010

Install Apps from PPAs without Using the Terminal


Here's a really nice Lucid feature. In this video you can see that users can now add software from your PPA without using the CLI. They just need to get you deb line, and using the software center, they are good to go.

Quickly: 90 Seconds to Your PPA




Here's a quick video showing taking a finished Quickly app, setting the desktop and setup.py file, and then uploading to a PPA using $quickly share

Sunday, April 25, 2010

Create Your Own Games with Quickly Pygame

A couple of months ago I created a Quickly template with the goal of making it easy and fun to get started my games. The template doesn't have any "add" or "design" commands, but it does have all the other commands. The template creates a functioning arcade-style game, and then you provide you own artwork and start hacking the code to make your own gameplay.

$quickly tutorial ubuntu-pygame is the best way to get a detailed introduction into getting started making your own game, but here's some video of hacking the code. I hope it inspires you to try your hand at creating your own games.

Part 1: Create the game, copy in your artwork, and make the guy work the way you want


Part 2: Program the enemies


Part 3: Create a power up sprite, and manage collisions


Slip Cover: Creating Views

I've been doing a few minutes of work a day on slip-cover, working towards getting view editing pretty complete. Pretending that I want to create a view that simply lists all of the keys in a database, you can see here that you now can:

1. Click the "Add Button" above the views, which adds a row to the views that you can start editing. Here I start by naming the design document.
2. Then I name the view. Notice the view editor is not visible yet, as I have not completed specifying the design doc or the name for the view.
3. Then I can try out my map function, and also name the view.
Currently, the view gets automatically saved to the database when created. I suppose this is ok, since it is easy to delete. The view doesn't track the dirty state at all. I should probably do something so users remember to save their views after they edit them. Undo and cut/copy/paste will all be necessary for the map/reduce editors as well.

Saturday, April 24, 2010

Quickly and Quickly Widget Intro Videos

You probably saw that didrocks released another update for Quickly. It's chock full of bug fixes and tweaks based on the feedback from the last release.

About a week ago I made some updated intro videos to show Quickly in action, and highlight some key changes between Quickly in Karmic and Quickly in Lucid. They are all available in HD, so you switch to that when they start playing, it makes them waaay easier to read.

Part 1: Create a project and use Glade to edit the UI
Here you see that you use "quickly create ubuntu-application" instead of "quickly create ubuntu-project" to create an app. You also use "quickly design" instead of "quickly glade" to design the UI.


Part 2: Using CouchGrid
One of the key differences here is that CouchGrid is now in the quickly.widgets module instead of the desktopcouch module. The CouchGrid moved into quickly.widgets because it now extends the DictionaryGrid class. This brings a lot benefits:
  1. Automatic column type inference
  2. Ability to set column types so you get the correct renderers
  3. Correct sorting (for instance 11 > 9 in IntegerColumn, but "11" < "9" in string columns
And of course you get all the goodness of automatic desktopcouch persistence.


Part 3: Using GridFilter
GridFilter is a new class that provides automatic filtering UI for a DictionaryGrid or descendant such as CouchGrid.

Thursday, April 22, 2010

Slip Cover, Integrated View Editor for DesktopCouch

I removed the ViewDesignerDialog, and changed it to a ViewDesignerBox. Basically, a widget that is now embedded into Slip Cover. I also wrote some code to extract the views that currently exist in a database, and offer those under "Views" so you can click on them and see the views map function, and the views reduce function if it has one.

Besides editing views and trying out your edits, this lets you look at the databases you have and see how they work. In the example above, you can see how the views for your contacts are set up. Handy if you want a similar feature in one of your databases.



This screenshot shows two things. First, it shows the view I constructed to get the record type for each record in a database, and also whether the record has been deleted. It's a bit "meta", but the purpose of this is visible in the Record Types list. I use the view to list out the record types, and how many records are deleted and how many active.

Still a few missing features:
  1. The "Create View" button doesn't work yet (though shouldn't be too very hard to make)
  2. "Save View" also doesn't work yet.
  3. I want to add options for executing your view, such as Group and such.
  4. I want to add a bit more data about each database, and whether you can sync it or not. I'm thinking about doing this on the server info tab, maybe an editable DictionaryGrid?
Also, in terms of quickly-widgets, I hate writing the same notebook code for tabbed interfaces over and over again. We should have a quidget that makes it easy and fun, and handles close buttons on the tabs, has a free document menu, and has alt # navigation to documents.

Sunday, April 18, 2010

Desktop Couch View Editor

As I've been learning to use DesktopCouch, I've come to understand the key role that writing map and reduce functions play. Basically, a view is stored map function and optional reduce function. I still haven't quite figured out reduce functions, especially wrt rereduce.

Anyway, I was finding it way to tedious to iterate on views in iPython. A map or reduce function looks to DesktopCouch as a string, thought it is a function written in javascript. And there is no syntax highlighting, or really any help at all writing this function as they look like strings in gedit and iPython.

So yesterday, my ViewDesignDialog was born, and added to Slip Cover. Currently, it supports running a map/reduce function as a temp view. This has been very helpful for me already, as I've been able to finally write a map function gives me each record, it's record and type, and whether that record is active or deleted. I want this for the record types view in slip cover, so you can see if there are any active records associated with the record type. I might be able to go on and build an "undelete" feature which would be handy for undo actions in slip cover.

I will add a "Copy as DesktopCouch" code next, which will just put the code on the buffer so you can paste it into your Python code as desired. Also, I'll add "Save". To do this I'll need to do some work with design_docs.

Eventually, I expect Slip Cover will use this so you can create new views, and edit existing views, for a database using Slip Cover, in addition to having a handy tool for generating DesktopCouch code (or just browsing a database I suppose).

It's not integrated into Slip Cover to well atm. Maybe I'll get a chance to work more on this tonight, but I am plan to do some things that don't involve a keyboard for a while this weekend ;)


Thursday, April 15, 2010

Quickly For Lucid Release, Intro Video

Didrocks released quickly 0.4 yesterday. What a great contribution from didrocks! I suspect he his work will help tons of people have a really fun time writing Ubuntu apps. Read about the release in his detailed blog post.



In the meantime, I made a cheesy video last night, showing some of the changes in quickly, and how the new CouchGrid and GridFilter work.

[Note that it takes blip.tv a bit of time to render out a high def video like this, so if the video is not yet working, you can check back later.]

[D'oh .... stupid blip.tv bailed on encoding my video. I'll try again with smaller files. Stay tuned]

Monday, April 12, 2010

Today's Slip Cover Feature: New Database

So as planned, today I added the feature for creating databases. This was one of those sweet features where it ended up on the tip of previous coding, so it took literally a matter of minutes to implement. Just get a name from the users, create the database, then load it in the UI,

    def new_database(self, widget, data=None):
title = _("New database")
msg = _("Specify a name for the new database")
response, val = prompts.string(title,msg)
if response == gtk.RESPONSE_OK:
CouchDatabase(val, create=True)
self.load_db(self,val)

So now I have an end to end tool for designing my desktopcouch databases.

Use File->New and make a name for my database:
Get an empty screen for the database.
Use the "+" to create a new record type.
Use Add keys to add keys for record type.
Then add rows and fill in the data.

Sunday, April 11, 2010

Today's Slip Cover Feature(s): Add Record Types

Today I spent a few minutes to add an "Add Record Type" feature. As you can see, this was a matter of creating a button, and then in the handler, creating a single record with only that record type in it.
    def add_record_type(self, widget, data=None):
title = _("Add Record Type")
msg = _("""
Specify a string name for the record type. By convention, the
name should be a URL where you can document the user of the record type.
""")
response, val = prompts.string(title,msg,"http://wiki.ubuntu.com/")
if response == gtk.RESPONSE_OK:
r = Record({"record_type":val})
self.database.put_record(r)
self.record_type_grid.append_row({"Record Type":val,"editor":None})

After adding a record type, you can use add/delete rows/keys to full design and populate a data set. I'm kind of working inside out with regard to making a full desktopcouch designer. I started with modifying rows, then add/removing rows, then adding/removing keys, and now adding record types.


The next step is to implement New/Delete Database, and I'll a functional designer. I'll probably add Slip Cover to my PPA at that point.

There is no "Delete Record Type" function. This is because desktopcouch never permanently deletes a record, it only marks it as deleted, and as such does not return it when you query for records. This has the odd effect of making Record Types last forever. I am considering adding a "deleted count", and an "active count" column to the grid for the record types. This would take more Map/Reduce skills than I have right now, so would probably be a good thing for me to learn.

Saturday, April 10, 2010

Today's Slip Cover Feature(s): Deleting Keys, Refresh Button

Because I added "Add Key" yesterday, today I wanted to be symmetrical, so I added "delete keys". This turned out to be much more work. First, I ended up creating another quickly.prompt, and then I had to dive into the internals of CouchGrid, and also do some hair raising mucking with desktop couch.

quickly.prompts.checklist()
When the developer clicks the "delete keys" button, I wanted to present them with a list of keys they could choose from. And then have all of those get deleted. This seemed like the kind of thing that I'd want to use in other programs, so I decided to solve this problem generically by adding it to quickly.prompts.

I accomplished this by deriving from quickly.prompts.Prompt, and also creating a helper function. CheckListPrompt works as you would expect for prompt. You set it up by passing in some configuration info, including a dictionary of strings as keys, which will be labels for the checkboxes, and a bool value to determine if the box is checked by default.

You get back a response and val. The val is a dictionary of keys again, with bools for whether the checkboxes are active or not.

So to use the CheckListBox, I just pass in a dictionary of the keys for the CouchGrid, and then see if any were selecct:
       val = {}
for k in self.grid.keys:
val[k] = False
response, val = checklist(title, message, val)
if response == gtk.RESPONSE_OK:
#do stuff

Hair Raising Munging
Since "do stuff" is pretty destructive, I use a quickly.prompts.yes_no to confirm that the users wants to blow away all the data and screw up their database. Assuming they do want to delete the keys and values in the desktopcouch database, it turns out to be *not* easy to do the deletion without reading way into CouchGrid. The issue here is the couchdb reserves anything staring with a "_" for itself. But DictionaryGrid uses "__" as a convention to determine that a key should be hidden in the grid by default. So as a result of this CouchGrid munges _id and _rev and record_type before it reads to and from the database.

The second troublesome part was dealing with desktopcouch. It turns out that you can't just delete a key from a record. You have a delete the whole record and then create a new record without that key. so as a result the code deletes and recreates each and every row.

I really think this code belongs inside CouchGrid:
    def delete_keys_from_store(self, model, path, iter, keys_to_delete):
for k in keys_to_delete:
d = model.get_value(iter,len(self.grid.keys))
if k in d:
del(d[k])
if '__desktopcouch_id' in d:
keys = d.keys()
for k in keys:
if k.startswith("__desktopcouch"):
dc_key = k.split("__desktopcouch")[1]
d[dc_key] = d[k]
del(d[k])
if k == "__record_type":
d["record_type"] = d["__record_type"]
del(d["__record_type"])
self.database.delete_record(d['_id'])
del(d["_rev"])
del(d["_id"])
self.database.put_record(Record(d))

Who would ever be able to figure out to do all this?

Refresh
So after this the refresh function was trivial. Just tell the CouchGrid to reset, and then recreate the grid:
    def refresh(self, widget, data=None):
self.grid._refresh_treeview()
self.remove(self.filt)
self.filt = GridFilter(self.grid)
self.pack_start(self.filt, False, False)
self.reorder_child(self.filt,1)
self.filt.show()

desktopcouch Editor
So now with adding a removing records and keys, along with freshing, I have a functional desktopcouch editor. This tool has already proved a bit useful in getting a peak into certain database. However, I can't actually create new record types yet. Maybe tomorrow?

Friday, April 9, 2010

Today's Slip Cover Feature: Adding Columns

I started out wanting to add "refresh". However, I just wiped my netbook and set up Lucid UNE Beta 2 on it, so only had one database in my local desktopcouch and it didn't have any records. I didn't know how I'd test the feature. I haven't set up my Ubuntu One yet on this computer, because I've been waiting for gwibber to get fixed (it is!) so that I could test out the Social From the Start Experience.

This is a long winded way of saying that I decided to implement another feature first to make it easier for me to test refresh out, editing an existing database. The first step of this was to be able to add columns. So I added an "add column" button.

I used quickly.prompts to get the string from the user. To actually add the column required a bit of intimate knowledge of the internals of DictionaryGrid. It occurred to me that folks might want to be able to add a key/column to a Grid themselves, so I logged a bug to remind me to make this easier.

Since Fagan asked to see the code when I posts :) -
    def add_column(self, widget, data=None):
response, val = prompts.string("New Column","Please select a name for the new column")
if response == gtk.RESPONSE_OK:
self.grid.keys.append(val)
self.grid._refresh_treeview()

Thursday, April 8, 2010

Today's Slip Cover Feature: Adding/Removing Records

Took a few minutes of refactoring gtk code to push the UI around, but I added the ability to delete and rows to a desktopcouch database, by record type. Now I can remove annoying messages from my stream, or put fake ones in!

Bonus Feature

I added a grid filter to the UI (in literally less than a minute using quickly.widgets.GridFilter

Slip Cover, writing my own dev tools

I use desktopcouch quite a bit for the apps that I write. As a programmer, I want to be able to see into the database and confirm that my code is working, or make tweaks to the database so that I can test out new things. Also, I need to delete databases and records a lot.

Futon is the current tool provided for programmers to work with desktopcouch. However, I find it:
  1. Not work all the time
  2. Too complex UI wise
  3. A Couch tool, not a desktopcouch tool (a subtle but important distinction)
Thus, I started a new project for myself, slip-cover. Of course it's using Quickly 3.9.x ;) Also, the use of quickly-widgets made it very easy to boot strap this project. Though I am starting to see a need for some kind of quickly.widgets.DocumentTabs sort of thing.

The first iterations allows you to:
  1. view some desktopcouch instance info
  2. view records in a database by record type
  3. Modify existing records
I want to add some features based on my needs, in about this order:
  1. Ability to delete records
  2. Ability to delete a database
  3. Ability to add records
  4. Ability to add a field to records
  5. Ability to control whether a database syncs
  6. Ability to view views
  7. Ability to design views
Maybe a "feature a day" approach would work for this, especially as we close in on Lucid Final Freeze.

Monday, April 5, 2010

Fixing a real bug with the help of Winpdb

Over the last few years as I have gotten more and more addicted to programming Python, I have basically stopped using debuggers. This is not because I write bug free code, but because I prefer not use any of the IDEs available for Python, and I really don't much get along with pdb. I have always found that I need to invest a lot of effort into pdb to get what I want from it, and so now I default to "print line" debugging (using print statements to dump state to the console).

A couple of days ago, I decided to look into graphcial debuggers. I tried some of the Python IDEs out there, and they just really weren't for me. I saw Winpdb in the repositories, and decided to give it try. Today I have a bug that was a good test case for it. I imaging that I will be adding Winpdb to my toolkit on a more regular basis now.

The Bug
Over the weekend didrocks update quickly-widgets in universe for me. quikly-widgets provides the DictionaryGrid class, that I use in bughugger to display data from bdmurray's JSON searches. I check bughugger every morning to see what the desktop team is working on, and generally where we are in terms of the bugs assigned to use.

So when I run bughugger this morning, I saw this:


Oops, only columns. Obviously a bug in quickly-widgets broke bughugger, but where?

Starting the Debugger
So I fired up the Winpdb. First thing is to select the file to launch. So I choose File -> Launch, and navigate to the bin/buhgugger file. I select a line close to, but before where I want to break the program. Clicking in the channel there, are using F9 key, sets a breakpoint. The run button then runs that app and will stop at the first breakpoint it hits in the source.





Debugging
After stopping at the first breakpoint, I see that I need to set a breakpoint in the add_*_triage_page functions, as that's where bughugger starts to assemble the view. The "keys" variable determines what columns are created in the DictionaryGrid, so I decide to watch the keys get passed around. I can see that the keys are set correctly here.


I use "run to line" and "step into" to see that the keys are still correctly set at when BugsPane is being created.
So I run to where the DictionaryGrid is created. The fact that I depended on the order of arguments instead of using keywords looks a bit suspicious to me.


So I step into the constructor for the DictionaryGrid, and see that, in fact, I did change the order of the contructor parameters, so it's not surpriisng the app went a little haywire. I fixed the bug by changing the call to use keywords.
I think using Winpdb saved me tons of time and effort compared to using pdb, or print statement debugging. In any case, it was a matter of minutes to find this bug, do I could go on to fixing the next bug :)