MythTV  0.25-pre
treebuilders.cpp
Go to the documentation of this file.
00001 #include <mythcontext.h>
00002 #include "treebuilders.h"
00003 
00004 typedef struct {
00005     QString field;
00006     MetadataPtrList list;
00007 } Branch;
00008 
00009 typedef struct  {
00010    QString testStr;
00011    QString dispStr;
00012 } FieldSplitInfo;
00013 
00014 // arrays for different level of granularity in the tree
00015 // choose between them by using a global setting.  In an ideal
00016 // world we would generate these dynamically, but that turned
00017 // into more change than it was worth
00018 static FieldSplitInfo splitArray4[] =
00019 { 
00020   {"!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~", " (...)"},
00021   {"01234", " (0 1 2 3 4)" },
00022   {"56789", " (5 6 7 8 9)" },
00023   {"ABCDE", " (A B C D E)"},
00024   {"FGHIJ", " (F G H I J)"},
00025   {"KLMNO", " (K L M N O)"},
00026   {"PQRST", " (P Q R S T)"},
00027   {"UVWXYZ", " (U V W X Y Z)"}
00028 };
00029 
00030 static FieldSplitInfo splitArray16[] =
00031 { 
00032   {"!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~", " (...)"},
00033   {"01234", " (0 1 2 3 4)" },
00034   {"56789", " (5 6 7 8 9)" },
00035   {"AB", " (A B)"},
00036   {"CD", " (C D)"},
00037   {"EF", " (E F)"},
00038   {"GH", " (G H)"},
00039   {"IJ", " (I J)"},
00040   {"KL", " (K L)"},
00041   {"MN", " (M N)"},
00042   {"OP", " (O P)"},
00043   {"QR", " (Q R)"},
00044   {"ST", " (S T)"},
00045   {"UV", " (U V)"},
00046   {"WX", " (W X)"},
00047   {"YZ", " (Y Z)"}
00048 };
00049 
00050 static FieldSplitInfo splitArray29[] =
00051 { 
00052   {"!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~", " (...)"},
00053   {"01234", " (0 1 2 3 4)" },
00054   {"56789", " (5 6 7 8 9)" },
00055   {"A", " A"},
00056   {"B", " B"},
00057   {"C", " C"},
00058   {"D", " D"},
00059   {"E", " E"},
00060   {"F", " F"},
00061   {"G", " G"},
00062   {"H", " H"},
00063   {"I", " I"},
00064   {"J", " J"},
00065   {"K", " K"},
00066   {"L", " L"},
00067   {"M", " M"},
00068   {"N", " N"},
00069   {"O", " O"},
00070   {"P", " P"},
00071   {"Q", " Q"},
00072   {"R", " R"},
00073   {"S", " S"},
00074   {"T", " T"},
00075   {"U", " U"},
00076   {"V", " V"},
00077   {"W", " W"},
00078   {"X", " X"},
00079   {"Y", " Y"},
00080   {"Z", " Z"}
00081 };
00082 
00083 const int kSplitArray4_Max = sizeof splitArray4 / sizeof splitArray4[0];
00084 const int kSplitArray16_Max = sizeof splitArray16 / sizeof splitArray16[0];
00085 const int kSplitArray29_Max = sizeof splitArray29 / sizeof splitArray29[0];
00086 
00087 static QString thePrefix = "the ";
00088 
00089 MusicTreeBuilder::MusicTreeBuilder() 
00090 {
00091     m_depth = -1;
00092 }
00093 
00094 MusicTreeBuilder::~MusicTreeBuilder() 
00095 {
00096 }
00097 
00098 void MusicTreeBuilder::makeTree(MusicNode *root, const MetadataPtrList &metas) 
00099 {
00100     m_depth++;
00101         
00102     typedef QMap<QString, Branch*> BranchMap;
00103     BranchMap branches;
00104     
00105     MetadataPtrList::const_iterator it = metas.begin();
00106     for (; it != metas.end(); ++it)
00107     {
00108         Metadata *meta = *it;
00109         if (isLeafDone(meta)) 
00110         {
00111             root->addLeaf(meta);
00112         } 
00113         else 
00114         {
00115             QString field = getField(meta);
00116             QString field_key = field.toLower();
00117 
00118             if (field_key.left(4) == thePrefix) 
00119                 field_key = field_key.mid(4);
00120 
00121             Branch *branch = branches[field_key];
00122             if (branch == NULL) 
00123             {
00124                 branch = new Branch;
00125                 branch->field = field;
00126                 branches[field_key] = branch;
00127             }
00128             branch->list.append(meta);
00129         }
00130     }
00131 
00132     for (BranchMap::iterator it = branches.begin(); it != branches.end(); ++it) 
00133     {
00134         Branch *branch = *it;
00135         MusicNode *sub_node = createNode(branch->field);
00136         root->addChild(sub_node);
00137         makeTree(sub_node, branch->list);
00138         delete branch;
00139     }
00140 
00141     m_depth--;
00142 }
00143 
00144 class MusicFieldTreeBuilder : public MusicTreeBuilder 
00145 {
00146   public:
00147     MusicFieldTreeBuilder(const QString &paths) 
00148     {
00149         m_paths = paths.split(' ', QString::SkipEmptyParts);
00150     }
00151 
00152     ~MusicFieldTreeBuilder() 
00153     {
00154     }
00155     
00156     void makeTree(MusicNode *root, const MetadataPtrList &metas) 
00157     {
00158         if (getDepth() + 2 >= m_paths.size()) 
00159         {
00160             root->setLeaves(metas);
00161             return;
00162         }
00163 
00164         MusicTreeBuilder::makeTree(root, metas);
00165     }
00166     
00167 protected:
00168     MusicNode *createNode(const QString &title) 
00169     {
00170         return new MusicNode(title, m_paths[getDepth()]);
00171     }
00172 
00173     bool isLeafDone(Metadata *) 
00174     {
00175         return false;
00176     }
00177     
00178     QString getField(Metadata *meta) 
00179     {
00180         QString field = m_paths[getDepth()];
00181         
00182         if (field == "splitartist1" || 
00183             field == "splitartist") 
00184         {
00185             return getSplitField(meta, field);
00186         } 
00187 
00188         QString data;
00189         meta->getField(field, &data);
00190         return data;
00191     }
00192 
00193 private:
00194     QStringList m_paths;
00195     QMap<QChar, QString> m_split_map;
00196 
00197     QString getSplitField(Metadata *meta, const QString &field) 
00198     {
00199         QString firstchar_str = meta->FormatArtist().trimmed();
00200 
00201         if (firstchar_str.left(4).toLower() == thePrefix) 
00202             firstchar_str = firstchar_str.mid(4,1).toUpper();
00203         else 
00204             firstchar_str = firstchar_str.left(1).toUpper();
00205         
00206         QChar firstchar = firstchar_str[0];
00207         QString split = m_split_map[firstchar];
00208         
00209         if (split.isEmpty()) 
00210         {
00211             if (field == "splitartist1") 
00212             {
00213                 split = QObject::tr("Artists") + " (" + firstchar + ")";
00214                 m_split_map[firstchar] = split;
00215             } 
00216             else 
00217             {
00218                 QString artistGrouping = gCoreContext->GetSetting("ArtistTreeGroups", "none");
00219                 if (artistGrouping == "2") 
00220                 {
00221                     int split_max = kSplitArray29_Max;
00222                     FieldSplitInfo *splits = splitArray29;            
00223                 
00224                     for(int i = 0; i < split_max; i++) 
00225                     {
00226                         if (splits[i].testStr.contains(firstchar)) 
00227                         {
00228                             split = QObject::tr("Artists") + splits[i].dispStr;
00229                             m_split_map[firstchar] = split;
00230                             break;
00231                         }
00232                     }
00233                 }
00234                 else
00235                 {
00236                     if (artistGrouping == "1")
00237                     {
00238                         int split_max = kSplitArray16_Max;
00239                         FieldSplitInfo *splits = splitArray16;            
00240                     
00241                         for(int i = 0; i < split_max; i++) 
00242                         {
00243                             if (splits[i].testStr.contains(firstchar)) 
00244                             {
00245                                 split = QObject::tr("Artists") + splits[i].dispStr;
00246                                 m_split_map[firstchar] = split;
00247                                 break;
00248                             }
00249                         }
00250                     }
00251                     else
00252                     {
00253                         // old behaviour is the default
00254                         int split_max = kSplitArray4_Max;
00255                         FieldSplitInfo *splits = splitArray4;            
00256                     
00257                         for(int i = 0; i < split_max; i++) 
00258                         {
00259                             if (splits[i].testStr.contains(firstchar)) 
00260                             {
00261                                 split = QObject::tr("Artists") + splits[i].dispStr;
00262                                 m_split_map[firstchar] = split;
00263                                 break;
00264                             }
00265                         }
00266                     }
00267                 }
00268             }
00269         }
00270 
00271         if (split.isEmpty()) 
00272         {
00273             split = QObject::tr("Artists") + " (" + firstchar + ")";
00274             m_split_map[firstchar] = split;
00275         }
00276 
00277         return split;
00278     }
00279 };
00280 
00281 class MusicDirectoryTreeBuilder : public MusicTreeBuilder 
00282 {
00283   public:
00284     MusicDirectoryTreeBuilder() 
00285     {
00286         m_startdir = gCoreContext->GetSetting("MusicLocation");
00287     }
00288 
00289     ~MusicDirectoryTreeBuilder() 
00290     {
00291         for (MetaMap::iterator it = m_map.begin(); it != m_map.end(); ++it)
00292             delete *it;
00293     }
00294 
00295 protected:
00296     MusicNode *createNode(const QString &title) 
00297     {
00298         return new MusicNode(title, "directory");
00299     }
00300 
00301     bool isLeafDone(Metadata *meta) 
00302     {
00303         return getDepth() + 1 >= getPathsForMeta(meta)->size();
00304     }
00305 
00306     QString getField(Metadata *meta) 
00307     {
00308         return getPathsForMeta(meta)->operator[](getDepth());
00309     }
00310 
00311   private:
00312     inline QString getStartdir(void) { return m_startdir; }
00313 
00314     QStringList* getPathsForMeta(Metadata *meta) 
00315     {
00316         QStringList *paths = m_map[meta];
00317 
00318         if (paths)
00319             return paths;
00320 
00321         QString filename = meta->Filename().remove(0, getStartdir().length());
00322         paths = new QStringList(filename.split('/'));
00323         m_map[meta] = paths;
00324         
00325         return paths;
00326     }
00327 
00328     typedef QMap<Metadata*,QStringList*> MetaMap;
00329     MetaMap m_map;
00330     QString m_startdir;
00331 
00332 };
00333 
00334 MusicTreeBuilder *MusicTreeBuilder::createBuilder(const QString &paths) 
00335 {
00336     if (paths == "directory")
00337         return new MusicDirectoryTreeBuilder();
00338 
00339     return new MusicFieldTreeBuilder(paths);
00340 }
00341 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends