Others can speak more eloquently than I can about the significance of mozilla.org's birth. I'll put it in much simpler terms: I owe my professional career to that event and the years that followed.
I have always been a fan of the Mozilla code base - dating all the way back to my early high school years when Netscape was appearing on the scene. Shortly after I'd finished writing my book on JavaScript, I discovered Mozilla's user-interface had a huge JavaScript presence in it. After a few years tinkering around in the Mozilla codebase, a recruiting agency contacted me and asked if I wanted to do that for a living. To which my answer then - and now - is "absolutely, yes!"
A few years later, I'm working at Skyfire Labs, Inc., (which coincidentally appeared today in the Wall Street Journal), and I'm having the time of my life. I'm doing what I wanted to do, and I'm getting paid nicely to do it. What could possibly be better than that?
So when someone wants to throw a party to celebrate what Mozilla's done for the past ten years - not just at the beginning - I'm there. Mozilla technology made it possible for me to earn a decent living doing what I do best. This community made it possible.
So, to everyone who's written a line of code, filed a bug, written a testcase, figured out how to make it easier on others, or just written down what it does and how to use it... thanks.
I love XUL trees. I even smoke them from time to time. But what I don't like is trying to build a hierarchy of objects in them - even though that's probably the best use for them.
Imagine that you want to show this tree of objects, with properties of each object horizontally, and the objects themselves laid out vertically, indented and illustrated to show which objects have which parent objects. DOM Inspector does this with DOM nodes all the time. My chrome registry viewer code does something similar for files (file systems are tree-like), and when you want to see the properties of an object, JS object inspection is usually through a tree. Even Venkman uses trees to show you functions in a file or webpage.
Still, for every different object tree I've come across, there's a different view that has to be built. Usually it's custom-built for that tree. So you've got two options: build your own view, from scratch, every time... or build a XUL tree DOM and let Gecko's own tree utilities show it to you.
Believe it or not, I've tried both approaches... and finally decided to roll my own baseline solution. (If someone else has done this before, please let me know. It's best to have this in a common place.) More details in the extended section.
Here's the kind of image that comes to mind every time I've looked at the nsITreeView interface:
Seriously, what in the name of (it's Easter weekend, I don't care to push my luck) what in the world is this? At least half the methods on it deal with row-specific or cell-specific details. Couldn't the people who work with this just given me a nsITreeRow interface and a getRow() method on the tree view?!?
I mean, it feels so dirty. It feels... procedural. Not object-oriented at all. How do you map a row in this tree to an object? You don't through this interface - because there's no row to grab.
It's also an interface with a lot of methods on it to implement. Yeeeuck. It's not immediately obvious which ones you need, and when. I've never truly understood this tree view stuff, even with XULPlanet's tutorial lending a hand.
I do understand treeitems, treechildren, treerow, and the like, though. It's DOM! It's something we already have! It's easy to inspect, to debug! It's familiar!
This was my preferred method of building trees for five years. Never mind the various people who kept telling me that tree views were so much better, ignoring me when I said, "No, make this a DOM set of trees, that doesn't need a lot to understand." It's simple. I like simple.
Until two or three months ago, when I discovered nsTreeContentView. For those of you who don't know about it, this is what takes your pretty DOM-based XUL tree and converts it into a nsITreeView object.
So here's what happens: My app spends a lot of time crafting this oh-so-nice, fifteen-levels-deep, memory-crushing, CPU-melting DOM fragment. My program then appends it, forcing nsTreeContentView to go to work, ripping that fragment apart and creating... a nsITreeView that I did everything to avoid dealing with, and which you just waited far too long for. Not to mention the bootstrapping I have to put on top of that DOM tree to bind each row to some object.
There are a few things that are more efficient than this approach...
So finally I said, "enough of this." If I'm going to build a tree for objects, I'm going to do it right. I'm going to create a generalized tree view component, reading from both the tree and from objects, to show the object hierarchy. I'm going to define a very simple, and very flexible, API that my component's users can build in and make it all work.
The first concept is that tree columns define what the cells show. So
let's just go ahead and define a propertyname attribute to stick
on each <xul:treecol/>. element. We still need those,
anyway. For more complex properties, define a fallback by allowing the tree's
author to set a function on the column element. I do this through the DOM 3
UserData API.
The second concept is that there's a 1:1 mapping between rows and objects.
That is, for each row, there should be exactly one object, and vice versa. So,
at least internally, we need a TreeRow class to store a reference
to the original objects.
The third concept is that the tree view needs to know how to get child objects of a given object. To do that, the tree view requires you to pass in a function which takes an object and returns an array of objects, which you say are children of that object.
The fourth concept is to provide a way to add top-level objects to this tree. Every DOM tree has a root node, every file system has a few items at the top. A generic tree view class can't know about them beforehand, so you have to tell it about them.
Put these four together, and you have enough to build a generic algorithm, a generic "class tree viewer".
Sample chrome code (copied, altered from the XUL Tutorial on developer.mozilla.org)
Element and MatterState represent (in this case) two similar classes which
live in the same tree - so really, you'd only need one of them. One column has
a propertyname attribute on it. The other one (further down in
the init() function) has a cellGetter function on it.
The getObjectChildren() function tells the tree view how to go from
one object to its children. Everything else is just raw data, initializing the
tree and the tree view, and adding top-level objects to the tree. It's really
just that simple, and pretty light-weight.
Now, I will admit this ClassTreeView is not complete.
For instance, it's read-only, and doesn't yet support progress meters, check
boxes, etc. I don't need those at this point, and to me it's just more
complexity (see nsITreeView for details). As a starting point for showing a
true object hierarchy, though, it's good enough. If you know tree views and
want to finish this, patches accepted!
API-wise, it's a "best guess". I designed this to work based on my needs and understanding. Maybe there are better approaches - but for this particular problem, I think it's a good start.
The one true weakness to ClassTreeView is that content web
pages cannot use it. The reason for that is buried at the end of the
nsITreeView.idl file: the nsINativeTreeView interface. So perhaps
I will someday rewrite this in C++ code - after I figure out C++-to-JavaScript
interfaces, and with a lot of reviews to make sure I get it right - and I'll
make it available to the Web. (Then again, you don't see a whole lot of XUL
on the Web... maybe for reasons like this.)
Over the last several weeks, I've been having this gnawing urge to restart work on Verbosio. It's been getting stronger, to the point where I just can't keep quiet about it: I'm getting back into it, and looking forward to completing my work on an 0.1 "proof-of-concept" XML editor.
Since I put Verbosio to sleep several months ago, I've had a number of thoughts:
Ultimately, I'm still not sure of where this Verbosio project will take me - or where I'll take it. But I take heart in the fact that I still don't see anyone doing anything remotely like what I have in mind for Verbosio. Sure, it's hard to do (as I've said before), but I have a vision, and that makes the years of effort worthwhile.
Thanks for reading!
As a guy who works on Firefox code on a regular basis, and as someone who recently started reading CodingHorror again, I thought it worth pointing this post out. Jeff Atwood is usually insightful.
That doesn't mean I agree with him, and I certainly don't, here. I'm posting this in the hopes that someone from our Firefox community will respond. Mr. Atwood is one of those voices worth hearing and answering, in my opinion.