Index: mythmusic/mythmusic/mythmusic.pro
===================================================================
--- mythmusic/mythmusic/mythmusic.pro	(revision 8915)
+++ mythmusic/mythmusic/mythmusic.pro	(working copy)
@@ -36,6 +36,7 @@
 HEADERS += goom/ifs.h goom/lines.h goom/mythgoom.h goom/drawmethods.h
 HEADERS += goom/mmx.h goom/mathtools.h goom/tentacle3d.h goom/v3d.h
 HEADERS += editmetadata.h smartplaylist.h search.h genres.h
+HEADERS += treebuilders.h
 
 SOURCES += cddecoder.cpp cdrip.cpp decoder.cpp 
 SOURCES += flacdecoder.cpp flacencoder.cpp maddecoder.cpp main.cpp
@@ -50,3 +51,4 @@
 SOURCES += goom/ifs.c goom/ifs_display.c goom/lines.c goom/surf3d.c 
 SOURCES += goom/zoom_filter_mmx.c goom/zoom_filter_xmmx.c goom/mythgoom.cpp
 SOURCES += avfdecoder.cpp editmetadata.cpp smartplaylist.cpp search.cpp
+SOURCES += treebuilders.cpp
Index: mythmusic/mythmusic/metadata.cpp
===================================================================
--- mythmusic/mythmusic/metadata.cpp	(revision 8915)
+++ mythmusic/mythmusic/metadata.cpp	(working copy)
@@ -11,53 +11,8 @@
 #include <mythtv/mythdbcon.h>
 
 #include "metadata.h"
+#include "treebuilders.h"
 
-struct FieldSplitInfo {
-   QString testStr;
-   QString dispStr;
-};
-
-static FieldSplitInfo splitArray4[] =
-{ 
-  {"ABCDE", " (A B C D E)"},
-  {"FGHIJ", " (F G H I J)"},
-  {"KLMNO", " (K L M N O)"},
-  {"PQRST", " (P Q R S T)"},
-  {"UVWXYZ", " (U V W X Y Z)"}
-};
-const int kSplitArray4_Max = sizeof splitArray4 / sizeof splitArray4[0];
-
-static FieldSplitInfo splitArray1[] =
-{ 
-  {"A", " (A)"},
-  {"B", " (B)"},
-  {"C", " (C)"},
-  {"D", " (D)"},
-  {"E", " (E)"},
-  {"F", " (F)"},
-  {"G", " (G)"},
-  {"H", " (H)"},
-  {"I", " (I)"},
-  {"J", " (J)"},
-  {"K", " (K)"},
-  {"L", " (L)"},
-  {"M", " (M)"},
-  {"N", " (N)"},
-  {"O", " (O)"},
-  {"P", " (P)"},
-  {"Q", " (Q)"},
-  {"R", " (R)"},
-  {"S", " (S)"},
-  {"T", " (T)"},
-  {"U", " (U)"},
-  {"V", " (V)"},
-  {"W", " (W)"},
-  {"X", " (X)"},
-  {"Y", " (Y)"},
-  {"Z", " (Z)"},
-};
-const int kSplitArray1_Max = sizeof splitArray1 / sizeof splitArray1[0];
-
 static QString thePrefix = "the ";
 
 bool operator==(const Metadata& a, const Metadata& b)
@@ -123,11 +78,10 @@
 {
     if (format == "cast") 
     {
-        int artist_cmp = qstrcmp (Artist(), other->Artist());
-        int title_cmp = qstrcmp (Title(), other->Title());
+        int artist_cmp = Artist().lower().localeAwareCompare(other->Artist().lower());
         
         if (artist_cmp == 0) 
-            return title_cmp;
+            return Title().lower().localeAwareCompare(other->Title().lower());
         
         return artist_cmp;
     } 
@@ -137,12 +91,11 @@
     }
 }
 
-bool Metadata::isInDatabase(QString startdir)
+bool Metadata::isInDatabase()
 {
     bool retval = false;
 
-    QString sqlfilename = filename;
-    sqlfilename = filename.remove(0, startdir.length());
+    QString sqlfilename = filename.remove(0, m_startdir.length());
 
     MSqlQuery query(MSqlQuery::InitCon());
     query.prepare("SELECT artist,compilation_artist,album,title,genre,year,tracknum,"
@@ -175,7 +128,7 @@
     return retval;
 }
 
-void Metadata::dumpToDatabase(QString startdir)
+void Metadata::dumpToDatabase()
 {
     if (artist == "")
         artist = QObject::tr("Unknown Artist");
@@ -188,8 +141,7 @@
     if (genre == "")
         genre = QObject::tr("Unknown Genre");
 
-    QString sqlfilename = filename;
-    sqlfilename = filename.remove(0, startdir.length());
+    QString sqlfilename = filename.remove(0, m_startdir.length());
 
     // Don't update the database if a song with the exact same
     // metadata is already there
@@ -306,10 +258,10 @@
 inline QString Metadata::formatReplaceSymbols(const QString &format)
 {
   QString rv = format;
-  rv.replace(QRegExp("COMPARTIST"), compilation_artist);
-  rv.replace(QRegExp("ARTIST"), artist);
-  rv.replace(QRegExp("TITLE"), title);
-  rv.replace(QRegExp("TRACK"), QString("%1").arg(tracknum, 2));
+  rv.replace("COMPARTIST", compilation_artist);
+  rv.replace("ARTIST", artist);
+  rv.replace("TITLE", title);
+  rv.replace("TRACK", QString("%1").arg(tracknum, 2));
   return rv;
 }
 
@@ -372,9 +324,8 @@
 }
 
 
-void Metadata::updateDatabase(QString startdir)
+void Metadata::updateDatabase()
 {
-    startdir = startdir; 
     // only save to DB if something changed
     //if (!hasChanged())
     //    return;
@@ -454,51 +405,6 @@
     }
 }
 
-bool Metadata::areYouFinished(uint depth, uint treedepth, const QString &paths, const QString &startdir)
-{
-    if(paths == "directory")
-    {
-        //  have we made it to directory just above the file name?
-
-        QString working = filename;
-        working.replace(QRegExp(startdir), QString(""));
-        working = working.section('/', depth);
-        if(working.contains('/') < 1)
-        {
-            return true;
-        }
-    }
-    else
-    {
-        if(depth + 1 >= treedepth)
-        {
-            return true;
-        }
-    }
-    return false;
-}
-
-void Metadata::getField(const QStringList &tree_levels, QString *data, const QString &paths, const QString &startdir, uint depth)
-{
-    if(paths == "directory")
-    {
-        //  Return directory values as if they were 
-        //  real metadata/TAG values
-        
-        QString working = filename;
-        working.replace(QRegExp(startdir), QString(""));
-        working.replace(QRegExp("/[^/]*$"), QString(""));
-
-        working = working.section('/', depth, depth);        
-        
-        *data = working;
-    }
-    else
-    {
-        getField(tree_levels[depth], data);
-    }
-}
-
 void Metadata::getField(const QString &field, QString *data)
 {
     if (field == "artist")
@@ -509,48 +415,6 @@
         *data = FormatTitle();
     else if (field == "genre")
         *data = genre;
-    else if (field == "splitartist")
-    {
-        bool set = false;
-        QString firstchar;
-        if (FormatArtist().left(4).lower() == thePrefix)
-            firstchar = FormatArtist().mid(4, 1).upper();
-        else
-            firstchar = FormatArtist().left(1).upper();
-
-        for (int i = 0; i < kSplitArray4_Max; i++)
-        {
-            if (splitArray4[i].testStr.contains(firstchar))
-            {
-                set = true;
-                *data = QObject::tr("Artists") + splitArray4[i].dispStr;
-            }
-        }
-
-        if (!set)
-            *data = QObject::tr("Artists") + " (" + firstchar + ")";
-    }
-    else if (field == "splitartist1")
-    {
-        bool set = false;
-        QString firstchar;
-        if (FormatArtist().left(4).lower() == thePrefix)
-            firstchar = FormatArtist().mid(4, 1).upper();
-        else
-            firstchar = FormatArtist().left(1).upper();
-
-        for (int i = 0; i < kSplitArray1_Max; i++)
-        {
-            if (splitArray1[i].testStr.contains(firstchar))
-            {
-                set = true;
-                *data = QObject::tr("Artists") + splitArray1[i].dispStr;
-            }
-        }
-
-        if (!set)
-            *data = QObject::tr("Artists") + " (" + firstchar + ")";
-    }
     else
     {
         cerr << "metadata.o: Something asked me to return data about a field called " << field << endl ;
@@ -708,10 +572,8 @@
     //  How should we sort?
     setSorting(path_assignment);
 
-    MusicNode::SetStaticData(startdir, paths);
+    root_node = new MusicNode(QObject::tr("All My Music"), paths);
 
-    root_node = new MusicNode("root", tree_levels, 0);
-
     //
     //  Start a thread to do data
     //  loading and sorting
@@ -721,7 +583,6 @@
     startLoading();
 
     all_music.setAutoDelete(true);
-    top_nodes.setAutoDelete(true);
     
     last_listed = -1;
 }
@@ -729,7 +590,6 @@
 AllMusic::~AllMusic()
 {
     all_music.clear();
-    top_nodes.clear();
 
     delete root_node;
 
@@ -790,15 +650,12 @@
                         "FROM musicmetadata "
                         "ORDER BY intid;";
 
-    QString filename;
-    QString startdir = gContext->GetSetting("MusicLocation");
-    startdir = QDir::cleanDirPath(startdir);
-    if (!startdir.endsWith("/"));
-        startdir += "/";
+    QString filename, artist, album, title;
 
     MSqlQuery query(MSqlQuery::InitCon());
     query.exec(aquery);
 
+    root_node->clear();
     all_music.clear();
 
     numPcs = query.size() * 2;
@@ -812,12 +669,24 @@
             if (!filename.contains("://"))
                 filename = startdir + filename;
 
+            artist = QString::fromUtf8(query.value(1).toString());
+            if (artist.isEmpty())
+                artist = QObject::tr("Unknown Artist");
+
+            album = QString::fromUtf8(query.value(3).toString());
+            if (album.isEmpty())
+                album = QObject::tr("Unknown Album");
+
+            title = QString::fromUtf8(query.value(4).toString());
+            if (title.isEmpty())
+                title = QObject::tr("Unknown Title");
+
             Metadata *temp = new Metadata(
                 filename,
-                QString::fromUtf8(query.value(1).toString()),
+                artist,
                 QString::fromUtf8(query.value(2).toString()),
-                QString::fromUtf8(query.value(3).toString()),
-                QString::fromUtf8(query.value(4).toString()),
+                album,
+                title,
                 QString::fromUtf8(query.value(5).toString()),
                 query.value(6).toInt(),
                 query.value(7).toInt(),
@@ -882,21 +751,6 @@
 void AllMusic::sortTree()
 {
     root_node->sort();
-
-    //  sort top level nodes
-    
-    top_nodes.sort();
-    
-    //  tell top level nodes to sort from themselves 
-    //  downwards
-
-    QPtrListIterator<MusicNode> iter(top_nodes);
-    MusicNode *crawler;
-    while ( (crawler = iter.current()) != 0 )
-    {
-        crawler->sort();
-        ++iter;
-    }
 }
 
 void AllMusic::printTree()
@@ -905,13 +759,6 @@
 
     cout << "Whole Music Tree" << endl;
     root_node->printYourself(0);
-    QPtrListIterator<MusicNode> iter( top_nodes );
-    MusicNode *printer;
-    while ( (printer = iter.current()) != 0 )
-    {
-        printer->printYourself(1);
-        ++iter;
-    }
 }
 
 void AllMusic::buildTree()
@@ -926,12 +773,9 @@
     //  Select Music screen
     //
     
-    top_nodes.clear();
-    root_node->clearTracks();
-    
     QPtrListIterator<Metadata> an_iterator( all_music );
     Metadata *inserter;
-    QPtrList<Metadata> list;
+    MetadataPtrList list;
 
     while ( (inserter = an_iterator.current()) != 0 )
     {
@@ -942,81 +786,20 @@
         numLoaded++;
     }
 
-    intoTree(list);
+    MusicTreeBuilder *builder = MusicTreeBuilder::createBuilder (paths);
+    builder->makeTree (root_node, list);
+    delete builder;
 }
 
 void AllMusic::writeTree(GenericTree *tree_to_write_to)
 {
-    GenericTree *sub_node = tree_to_write_to->addNode(QObject::tr("All My Music"), 0);
-    sub_node->setAttribute(0, 0);
-    sub_node->setAttribute(1, 0);
-    sub_node->setAttribute(2, 0);
-    sub_node->setAttribute(3, 0);
-    
-
-    QPtrListIterator<MusicNode> iter( top_nodes );
-    MusicNode *traverse;
-    iter.toFirst();
-    int a_counter = 0;
-    while ( (traverse = iter.current()) != 0 )
-    {
-        traverse->setPlayCountMin(playcountMin);
-        traverse->setPlayCountMax(playcountMax);
-        traverse->setLastPlayMin(lastplayMin);
-        traverse->setLastPlayMax(lastplayMax);
-        traverse->writeTree(sub_node, a_counter);
-        ++a_counter;
-        ++iter;
-    }
+    root_node->writeTree(tree_to_write_to, 0);
 }
 
-bool AllMusic::putYourselfOnTheListView(TreeCheckItem *where, int how_many)
+bool AllMusic::putYourselfOnTheListView(TreeCheckItem *where)
 {
     root_node->putYourselfOnTheListView(where, false);
-
-    if (how_many < 0)
-    {
-        QPtrListIterator<MusicNode> iter(top_nodes);
-        MusicNode *traverse;
-        while ((traverse = iter.current()) != 0)
-        {
-            traverse->putYourselfOnTheListView(where, true);
-            ++iter;
-        }
-        return true;
-    }
-    else
-    {
-        if (last_listed < 0)
-            last_listed = 0;
-        
-        QPtrListIterator<MusicNode> iter(top_nodes);
-        MusicNode *traverse;
-        iter += last_listed;
-        int numb_this_round = 0;
-
-        while (true)
-        {
-            traverse = iter.current();
-            if (traverse)
-            {
-                traverse->putYourselfOnTheListView(where, true);
-                ++iter;
-                ++last_listed;
-                ++numb_this_round;
-                if(numb_this_round >= how_many)
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                return true;
-            }
-        }
-    }
-    cerr << "metadata.o: Control defied all possible logic and jumped way out here. World may end shortly. " << endl;
-    return false;
+    return true;
 }
 
 void AllMusic::putCDOnTheListView(CDCheckItem *where)
@@ -1041,52 +824,6 @@
     }  
 }
 
-
-void AllMusic::intoTree(QPtrList<Metadata> &list)
-{
-    uint depth = 0;
-    QString a_field = "";
-
-    QDict<MetadataPtrList> mapping;
-    QPtrListIterator<Metadata> iter( list );
-    MetadataPtrList *curList;
-    mapping.setAutoDelete(true);
-
-    Metadata *cur;
-    while ((cur = iter.current()) != 0)
-    {
-        if (cur->areYouFinished(depth, tree_levels.count(), paths, startdir))
-        {
-            //  special case, track is at root level
-            //  e.g. an mp3 in the root directory and
-            //  paths=directory
-            root_node->insert(cur);
-            ++iter;
-            continue;
-        }
-
-        cur->getField(tree_levels.first(), &a_field, paths, startdir, depth);
-        curList = mapping.find(a_field);
-        if (!curList)
-        {
-            curList = new MetadataPtrList;
-            mapping.insert(a_field, curList);
-        }
-        curList->append(cur);
-        ++iter;
-    }
-
-    QDictIterator<MetadataPtrList> rest(mapping);
-    while ((curList = rest.current()) != 0)
-    {
-        a_field = rest.currentKey();
-        MusicNode *new_one = new MusicNode(a_field, tree_levels, 0);
-        top_nodes.append(new_one);
-        new_one->intoTree(tree_levels, *curList, depth + 1);
-        ++rest;
-    }
-}
-
 QString AllMusic::getLabel(int an_id, bool *error_flag)
 {
     QString a_label = "";
@@ -1232,12 +969,13 @@
 void AllMusic::setSorting(QString a_paths)
 {
     paths = a_paths;
+    MusicNode::SetStaticData(startdir, paths);
+
     if (paths == "directory")
         return;
-    else
-        tree_levels = QStringList::split(" ", paths);
 
     //  Error checking
+    QStringList tree_levels = QStringList::split(" ", paths);
     QStringList::const_iterator it = tree_levels.begin();
     for (; it != tree_levels.end(); ++it)
     {
@@ -1265,26 +1003,15 @@
     }
 }
 
-MusicNode::MusicNode(QString a_title, QStringList tree_levels, uint depth)
+MusicNode::MusicNode(const QString &a_title, const QString &tree_level)
 {
     my_title = a_title;
-    if (m_paths == "directory")
-    {
-        my_level = "directory";
-    }
-    else
-    {
-        if (depth < tree_levels.count())
-            my_level = tree_levels[depth];
-        else
-        {
-            my_level = "I am confused";
-            cerr << "metadata.o: Something asked me to look up a StringList entry that doesn't exist" << endl ;
-        }
-       
-    }
-
+    my_level = tree_level;
     my_subnodes.setAutoDelete(true);
+    setPlayCountMin(0);
+    setPlayCountMax(0);
+    setLastPlayMin(0);
+    setLastPlayMax(0);
 }
 
 MusicNode::~MusicNode()
@@ -1311,74 +1038,6 @@
     m_RandomWeight = gContext->GetNumSetting("IntelliRandomWeight", 2);
 }
     
-void MusicNode::insert(Metadata* inserter)
-{
-    my_tracks.append(inserter);
-}
-
-void MusicNode::intoTree(QStringList tree_levels, 
-                         MetadataPtrList &list, uint depth)
-{
-    QString a_field = "";
-    QString a_lowercase_field = "";
-    QString a_title = "";
-    bool usesPath = false;
-
-    if (m_paths == "directory") 
-        usesPath = true;
-    else
-    {
-        if (depth + 1 >= tree_levels.count())
-        {
-            my_tracks = list;
-            return;
-        }
-    }
-
-    //  Search and create from my node downards
-
-    QDict<MetadataPtrList> mapping;
-    QPtrListIterator<Metadata> iter(list);
-    MetadataPtrList *curList;
-    mapping.setAutoDelete(true);
-
-    Metadata *cur;
-    while ((cur = iter.current()) != 0)
-    {
-        if (usesPath && cur->areYouFinished(depth, tree_levels.count(), m_paths, m_startdir))
-        {
-            insert(cur);
-            ++iter;
-            continue;
-        }
- 
-        cur->getField(tree_levels, &a_field, m_paths, m_startdir, depth);
-  
-        a_lowercase_field = a_field.lower();
-        if (a_lowercase_field.left(4) == "the ")
-            a_field = a_field.mid(4);
-  
-        curList = mapping.find(a_field);
-        if (!curList)
-        {
-            curList = new MetadataPtrList;
-            mapping.insert(a_field, curList);
-        }
-        curList->append(cur);
-        ++iter;
-    }
-  
-    QDictIterator<MetadataPtrList> rest(mapping);
-    while ((curList = rest.current()) != 0)
-    {
-        a_field = rest.currentKey();
-        MusicNode *new_one = new MusicNode(a_field, tree_levels, depth);
-        my_subnodes.append(new_one);
-        new_one->intoTree(tree_levels, *curList, depth + 1);
-        ++rest;
-    }
-}
-
 void MusicNode::putYourselfOnTheListView(TreeCheckItem *parent, bool show_node)
 {
     TreeCheckItem *current_parent;
@@ -1448,10 +1107,16 @@
         double lastplaydbl = a_track->LastPlay();
         double ratingValue = (double)(rating) / 10;
         double playcountValue, lastplayValue;
-        if (playcountMax == playcountMin) { playcountValue = 0; }
-        else { playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1); }
-        if (lastplayMax == lastplayMin) { lastplayValue = 0; }
-        else { lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1); }
+
+        if (playcountMax == playcountMin) 
+            playcountValue = 0; 
+        else 
+            playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1); 
+        if (lastplayMax == lastplayMin) 
+            lastplayValue = 0;
+        else 
+            lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
+
         double rating_value =  (m_RatingWeight * ratingValue + m_PlayCountWeight * playcountValue +
                                 m_LastPlayWeight * lastplayValue + m_RandomWeight * (double)rand() /
                                 (RAND_MAX + 1.0));
@@ -1546,8 +1211,10 @@
     QString title2 = itemB->getTitle().lower();
     
     // Cut "the " off the front of titles
-    title1 = (title1.lower().left(4) == thePrefix) ? title1.mid(4) : title1;
-    title2 = (title2.lower().left(4) == thePrefix) ? title2.mid(4) : title2;
+    if (title1.left(4) == thePrefix) 
+        title1 = title1.mid(4);
+    if (title2.left(4) == thePrefix) 
+        title2 = title2.mid(4);
 
-    return qstrcmp(title1, title2);
+    return title1.localeAwareCompare(title2);
 }
Index: mythmusic/mythmusic/treebuilders.h
===================================================================
--- mythmusic/mythmusic/treebuilders.h	(revision 0)
+++ mythmusic/mythmusic/treebuilders.h	(revision 0)
@@ -0,0 +1,120 @@
+#ifndef TREEBUILDERS_H_
+#define TREEBUILDERS_H_
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrdict.h>
+#include <qdict.h>
+
+#include "metadata.h"
+
+/** \class MusicTreeBuilder
+    \brief superclass for the objects that build trees of \p Metadata
+    
+    This is the interface for objects that builds trees of \p Metadata
+    objects into \p MusicNode objects.
+
+    The basic idea of operation is, that the superclass provices a
+    makeTree method that depends on the subclasses for a few methods
+    to determine which fields of the metadata objects are used in
+    building the tree and where the metadata objects go.
+
+    This means that the superclass is fairly generic and does not
+    itself operate on or query the metadata objects, but leaves that
+    to the subclass. It's only responsibility is to determine the
+    branches that go into the tree and then add metadata objects as
+    leafs to the appropriate nodes.
+
+    Ie. if you wanted to build the MythMusic tree based on the size of
+    the audio files by implementing a \p MusicSizeTreeBuilder, the
+    approach would be to get \p MusicSizeTreeBuilder::getField return
+    the number of MB or KB blocks depending on the current depth as
+    obtained by \p getDept. Then you could either overload \p makeTree
+    to stop at a certain depth (like \p MusicFieldBuilder does) or
+    make \p MusicSizeTreeBuilder::isLeafDone return true if you've
+    reached the desired granularity.
+
+    \note This method is fairly generic, and uses very little of the
+    interfaces of \p MusicNode and \p Metadata, so it may someday be
+    made more generic and of use to other plugins that needs trees.
+
+    \note Calling this repeated using the same or new instance on the
+    same root node (ie. to progressively populate it) hasn't been
+    tested.
+ */
+class MusicTreeBuilder 
+{
+  public:
+    virtual ~MusicTreeBuilder();
+
+    /** \fn Create a tree using the list of \p Metadata objects and add them to the given root.
+
+        This method will recurse and operate of the list the metadata
+        objects in \p metas. It's implementation may and probably will
+        differ depending on the subclass of builder you've obtained,
+        depending on the kind of tree it builds.
+
+        It relies heavily on subclasses implementing \p
+        MusicTreeBuilder::isLeafDone and \p MusicTreeBuilder::getField
+        for operation, and for performance, the subclasses should
+        cache computed data in these methods as efficiently as possible.
+     */
+    virtual void makeTree(MusicNode *root, const MetadataPtrList &metas);
+
+    /** \fn Create an \p MusicTreeBuilder for the appropriate path.
+
+        Returns a \p MusicTreeBuilder subclass for building directory
+        based or "artist album" field based trees.
+     */
+    static MusicTreeBuilder *createBuilder(const QString &paths);
+
+  protected:
+    MusicTreeBuilder();
+
+    /** \fn Allocates and returns a new \p MusicNode.
+
+        Implemented by the subclass. This method should allocate and a
+        return a \p MusicNode with the approriate "level" set.
+     */
+    virtual MusicNode *createNode(const QString &title) = 0;
+
+    /** \fn Determine is a \p Metadata should be track at the current depth.
+ 
+        Ie. the directory builder will return true if the given \p
+        Metadata's path at the current depth is the filename.
+
+         Gets called repeatedly from \p MusicTreeBuilder::makeTree
+         during tree creation and should only get called once
+         pr. depth pr. \p Metadata.
+     */
+    virtual bool isLeafDone(Metadata *m) = 0;
+
+    /** \fn Get the field value for the given \p Metadata at the current depth.
+
+         Ie. the field builder will call \p Metadata::getField with
+         the appropriate field name for the current dept.
+
+         Gets called repeatedly from \p MusicTreeBuilder::makeTree
+         during tree creation and may get called multiple times at the
+         same depth for the same \p Metadata.
+     */
+    virtual QString getField(Metadata *m) = 0;	
+
+    /** \fn Get the current depth during tree building.
+        
+        While \p MusicTreeBuilder::makeTree is recursing downwards to
+        build the tree, this method will return the current depth and
+        can/should be used in the subclass when implemented the
+        virtual methods. 
+
+        Ie. the directory builder can use this in isLeafDone to
+        determine if the \p Metadata object under consideration has no
+        more elements in it's path.
+     */
+    inline int getDepth(void) { return m_depth; }
+
+  private:
+    int m_depth;
+};
+
+#endif /* TREEBUILDERS_H_ */
Index: mythmusic/mythmusic/decoder.cpp
===================================================================
--- mythmusic/mythmusic/decoder.cpp	(revision 8915)
+++ mythmusic/mythmusic/decoder.cpp	(working copy)
@@ -107,7 +107,7 @@
 {
 
     Metadata *mdata = new Metadata(filename);
-    if (mdata->isInDatabase(musiclocation))
+    if (mdata->isInDatabase())
     {
         return mdata;
     }
Index: mythmusic/mythmusic/metadata.h
===================================================================
--- mythmusic/mythmusic/metadata.h	(revision 8915)
+++ mythmusic/mythmusic/metadata.h	(working copy)
@@ -126,13 +126,11 @@
     void setCompilation(bool state) { compilation = state; formattedartist = formattedtitle = ""; }
     bool determineIfCompilation(bool cd = false);
     
-    bool isInDatabase(QString startdir);
-    void dumpToDatabase(QString startdir);
-    void updateDatabase(QString startdir);
+    bool isInDatabase(void);
+    void dumpToDatabase(void);
+    void updateDatabase(void);
     void setField(const QString &field, const QString &data);
-    void getField(const QString &field, QString *data);
-    void getField(const QStringList& tree_levels, QString *data, const QString &paths, const QString &startdir, uint depth);
-    bool areYouFinished(uint depth, uint treedepth, const QString& paths, const QString& startdir);
+    void getField(const QString& field, QString *data);
     void fillData();
     void fillDataFromID();
     void persist();
@@ -209,22 +207,14 @@
 };
 
 class MusicNode
-{
-    //  Not a root of the music tree, and
-    //  not a leaf, but anything in the
-    //  middle
-    
+{    
   public:
   
-    MusicNode(QString a_title, QStringList tree_levels, uint depth);
+    MusicNode(const QString &a_title, const QString &tree_level);
    ~MusicNode();
 
-    void        insert(Metadata* inserter);
     QString     getTitle(){return my_title;}
-    void        intoTree(QStringList tree_levels, MetadataPtrList &list,
-                         uint depth);
     void        printYourself(int indent_amount);   // debugging
-    void        clearTracks() { my_tracks.clear(); }
     void        putYourselfOnTheListView(TreeCheckItem *parent, bool show_node);
     void        writeTree(GenericTree *tree_to_write_to, int a_counter);
     void        sort();
@@ -233,13 +223,21 @@
     void        setLastPlayMin(double tmp_min) { lastplayMin = tmp_min; }
     void        setLastPlayMax(double tmp_max) { lastplayMax = tmp_max; }
 
+    inline void addChild(MusicNode *child) { my_subnodes.append(child); }
+    inline void addLeaf(Metadata *leaf) { my_tracks.append(leaf); }
+    inline void setLeaves(MetadataPtrList leaves) { my_tracks = leaves; }
+
+    void clear(void) { 
+        my_tracks.clear(); 
+        my_subnodes.clear();
+    }
+
     static void SetStaticData(const QString &startdir, const QString &paths);
  
   private:
   
     MetadataPtrList     my_tracks;
     MusicNodePtrList    my_subnodes;
-    QDict<MusicNode>    my_subnode_hash;
     QString             my_title;
     QString             my_level;
 
@@ -297,9 +295,8 @@
     void        printTree();    // debugging
     void        sortTree();
     void        writeTree(GenericTree *tree_to_write_to);
-    void        intoTree(QPtrList<Metadata> &list);
     void        setSorting(QString a_paths);
-    bool        putYourselfOnTheListView(TreeCheckItem *where, int how_many);
+    bool        putYourselfOnTheListView(TreeCheckItem *where);
     void        putCDOnTheListView(CDCheckItem *where);
     bool        doneLoading(){return done_loading;}
     bool        cleanOutThreads();
@@ -310,7 +307,6 @@
   private:
   
     MetadataPtrList     all_music;
-    MusicNodePtrList    top_nodes;
     MusicNode           *root_node;
     
     int numPcs;
@@ -330,7 +326,6 @@
 
     QString     startdir;
     QString     paths;
-    QStringList tree_levels;
     
     
     MetadataLoadingThread   *metadata_loader;
Index: mythmusic/mythmusic/editmetadata.cpp
===================================================================
--- mythmusic/mythmusic/editmetadata.cpp	(revision 8915)
+++ mythmusic/mythmusic/editmetadata.cpp	(working copy)
@@ -488,7 +488,7 @@
 {
     cancelPopup();
 
-    m_metadata->updateDatabase(QString::null);
+    m_metadata->updateDatabase();
     *m_sourceMetadata = m_metadata;
     done(1);
 }
Index: mythmusic/mythmusic/treebuilders.cpp
===================================================================
--- mythmusic/mythmusic/treebuilders.cpp	(revision 0)
+++ mythmusic/mythmusic/treebuilders.cpp	(revision 0)
@@ -0,0 +1,246 @@
+#include <mythtv/mythcontext.h>
+#include "treebuilders.h"
+
+typedef struct {
+    QString field;
+    MetadataPtrList list;
+} Branch;
+
+typedef struct  {
+   QString testStr;
+   QString dispStr;
+} FieldSplitInfo;
+
+static FieldSplitInfo splitArray4[] =
+{ 
+  {"!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~", " (...)"},
+  {"01234", " (0 1 2 3 4)" },
+  {"56789", " (5 6 7 8 9)" },
+  {"ABCDE", " (A B C D E)"},
+  {"FGHIJ", " (F G H I J)"},
+  {"KLMNO", " (K L M N O)"},
+  {"PQRST", " (P Q R S T)"},
+  {"UVWXYZ", " (U V W X Y Z)"}
+};
+const int kSplitArray4_Max = sizeof splitArray4 / sizeof splitArray4[0];
+
+static QString thePrefix = "the ";
+
+MusicTreeBuilder::MusicTreeBuilder() 
+{
+    m_depth = -1;
+}
+
+MusicTreeBuilder::~MusicTreeBuilder() 
+{
+}
+
+void MusicTreeBuilder::makeTree(MusicNode *root, const MetadataPtrList &metas) 
+{
+    m_depth++;
+        
+    typedef QMap<QString, Branch*> BranchMap;
+    BranchMap branches;
+    
+    Metadata *meta;
+    QPtrListIterator<Metadata> iter(metas);
+    while ((meta = iter.current()) != 0) 
+    {
+        if (isLeafDone(meta)) 
+        {
+            root->addLeaf(meta);
+        } 
+        else 
+        {
+            QString field = getField(meta);
+            QString field_key = field.lower();
+
+            if (field_key.left(4) == thePrefix) 
+                field_key = field_key.mid(4);
+
+            Branch *branch = branches[field_key];
+            if (branch == NULL) 
+            {
+                branch = new Branch;
+                branch->field = field;
+                branches[field_key] = branch;
+            }
+            branch->list.append(meta);
+        }
+
+        ++iter;
+    }
+
+    for(BranchMap::iterator it = branches.begin(); it != branches.end(); it++) 
+    {
+        Branch *branch = it.data();
+        MusicNode *sub_node = createNode(branch->field);
+        root->addChild(sub_node);
+        makeTree(sub_node, branch->list);
+        delete branch;
+    }
+
+    m_depth--;
+}
+
+class MusicFieldTreeBuilder : public MusicTreeBuilder 
+{
+  public:
+    MusicFieldTreeBuilder(const QString &paths) 
+    {
+        m_paths = QStringList::split(' ', paths);
+    }
+
+    ~MusicFieldTreeBuilder() 
+    {
+    }
+    
+    void makeTree(MusicNode *root, const MetadataPtrList &metas) 
+    {
+        if ((uint)getDepth() + 2 >= m_paths.size()) 
+        {
+            root->setLeaves(metas);
+            return;
+        }
+
+        MusicTreeBuilder::makeTree(root, metas);
+    }
+    
+protected:
+    MusicNode *createNode(const QString &title) 
+    {
+        return new MusicNode(title, m_paths[getDepth()]);
+    }
+
+    bool isLeafDone(Metadata *) 
+    {
+        return false;
+    }
+    
+    QString getField(Metadata *meta) 
+    {
+        QString field = m_paths[getDepth()];
+        
+        if (field == "splitartist1" || 
+            field == "splitartist") 
+        {
+            return getSplitField(meta, field);
+        } 
+
+        QString data;
+        meta->getField(field, &data);
+        return data;
+    }
+
+private:
+    QStringList m_paths;
+    //QDict<QString> m_charToSplitMap;
+    QMap<QChar, QString> m_split_map;
+
+    QString getSplitField(Metadata *meta, const QString &field) 
+    {
+        QString firstchar_str = meta->FormatArtist().stripWhiteSpace();
+
+        if (firstchar_str.left(4).lower() == thePrefix) 
+            firstchar_str = firstchar_str.mid(4,1).upper();
+        else 
+            firstchar_str = firstchar_str.left(1).upper();
+        
+        QChar firstchar = firstchar_str[0];
+        QString split = m_split_map[firstchar];
+        
+        if (split.isEmpty()) 
+        {
+            if (field == "splitartist1") 
+            {
+                split = QObject::tr("Artists ") + "(" + firstchar + ")";
+                m_split_map[firstchar] = split;
+            } 
+            else 
+            {
+                int split_max = kSplitArray4_Max;
+                FieldSplitInfo *splits = splitArray4;            
+            
+                for(int i = 0; i < split_max; i++) 
+                {
+                    if (splits[i].testStr.contains(firstchar)) 
+                    {
+                        split = QObject::tr("Artists ") + splits[i].dispStr;
+                        m_split_map[firstchar] = split;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (split.isEmpty()) 
+        {
+            split = QObject::tr("Artists") + "(" + firstchar + ")";
+            m_split_map[firstchar] = split;
+        }
+
+        return split;
+    }
+};
+
+class MusicDirectoryTreeBuilder : public MusicTreeBuilder 
+{
+  public:
+    MusicDirectoryTreeBuilder() 
+    {
+        m_startdir = gContext->GetSetting("MusicLocation");
+    }
+
+    ~MusicDirectoryTreeBuilder() 
+    {
+        for(MetaMap::iterator it = m_map.begin(); it != m_map.end(); it++)
+            delete it.data();
+    }
+
+protected:
+    MusicNode *createNode(const QString &title) 
+    {
+        return new MusicNode(title, "directory");
+    }
+
+    bool isLeafDone(Metadata *meta) 
+    {
+        return(uint)getDepth() + 1 >= getPathsForMeta(meta)->size();
+    }
+
+    QString getField(Metadata *meta) 
+    {
+        return getPathsForMeta(meta)->operator[](getDepth());
+    }
+
+  private:
+    inline QString getStartdir(void) { return m_startdir; }
+
+    QStringList* getPathsForMeta(Metadata *meta) 
+    {
+        QStringList *paths = m_map[meta];
+
+        if (paths)
+            return paths;
+
+        QString filename = meta->Filename().remove(0, getStartdir().length());
+        paths = new QStringList(QStringList::split('/', filename));
+        m_map[meta] = paths;
+        
+        return paths;
+    }
+
+    typedef QMap<Metadata*,QStringList*> MetaMap;
+    MetaMap m_map;
+    QString m_startdir;
+
+};
+
+MusicTreeBuilder *MusicTreeBuilder::createBuilder(const QString &paths) 
+{
+    if (paths == "directory")
+        return new MusicDirectoryTreeBuilder();
+
+    return new MusicFieldTreeBuilder(paths);
+}
+
Index: mythmusic/mythmusic/databasebox.cpp
===================================================================
--- mythmusic/mythmusic/databasebox.cpp	(revision 8915)
+++ mythmusic/mythmusic/databasebox.cpp	(working copy)
@@ -189,10 +189,7 @@
         the_playlists->doneLoading())
     {
         //  Good, now lets grab some QListItems
-        //
-        //  Say ... I dunno ... 100 at a time?
-
-        if (all_music->putYourselfOnTheListView(allmusic, 100))
+        if (all_music->putYourselfOnTheListView(allmusic))
         {
             allmusic->setText(tr("All My Music"));
             fill_list_timer->stop();
Index: mythmusic/mythmusic/main.cpp
===================================================================
--- mythmusic/mythmusic/main.cpp	(revision 8915)
+++ mythmusic/mythmusic/main.cpp	(working copy)
@@ -67,7 +67,7 @@
     return decoder;
 }
 
-void AddFileToDB(const QString &directory, const QString &filename)
+void AddFileToDB(const QString &filename)
 {
     Decoder *decoder = getDecoder(filename);
 
@@ -75,7 +75,7 @@
     {
         Metadata *data = decoder->getMetadata();
         if (data) {
-            data->dumpToDatabase(directory);
+            data->dumpToDatabase();
             delete data;
         }
 
@@ -91,11 +91,11 @@
     MSqlQuery query(MSqlQuery::InitCon());
     query.prepare("DELETE FROM musicmetadata WHERE "
                   "filename = :NAME ;");
-    query.bindValue(":NAME", name.utf8());
+    query.bindValue(":NAME", filename.utf8());
     query.exec();
 }
 
-void UpdateFileInDB(const QString &directory, const QString &filename)
+void UpdateFileInDB(const QString &filename)
 {
     Decoder *decoder = getDecoder(filename);
 
@@ -108,7 +108,7 @@
         {
             disk_meta->setID(db_meta->ID());
             disk_meta->setRating(db_meta->Rating());
-            disk_meta->updateDatabase(directory);
+            disk_meta->updateDatabase();
         }
 
         if (disk_meta)
@@ -316,11 +316,11 @@
     for (iter = music_files.begin(); iter != music_files.end(); iter++)
     {
         if (*iter == kFileSystem)
-            AddFileToDB(directory, iter.key());
+            AddFileToDB(iter.key());
         else if (*iter == kDatabase)
             RemoveFileFromDB(directory, iter.key ());
         else if (*iter == kNeedUpdate)
-            UpdateFileInDB(directory, iter.key());
+            UpdateFileInDB(iter.key());
 
         file_checking->setProgress(++counter);
     }
