Ticket #1287: 8-trees.patch
File 8-trees.patch, 24.3 KB (added by , 18 years ago) |
---|
-
mythmusic/mythmusic/mythmusic.pro
36 36 HEADERS += goom/ifs.h goom/lines.h goom/mythgoom.h goom/drawmethods.h 37 37 HEADERS += goom/mmx.h goom/mathtools.h goom/tentacle3d.h goom/v3d.h 38 38 HEADERS += editmetadata.h smartplaylist.h search.h genres.h 39 HEADERS += treebuilders.h 39 40 40 41 SOURCES += cddecoder.cpp cdrip.cpp decoder.cpp 41 42 SOURCES += flacdecoder.cpp flacencoder.cpp maddecoder.cpp main.cpp … … 50 51 SOURCES += goom/ifs.c goom/ifs_display.c goom/lines.c goom/surf3d.c 51 52 SOURCES += goom/zoom_filter_mmx.c goom/zoom_filter_xmmx.c goom/mythgoom.cpp 52 53 SOURCES += avfdecoder.cpp editmetadata.cpp smartplaylist.cpp search.cpp 54 SOURCES += treebuilders.cpp -
mythmusic/mythmusic/metadata.cpp
11 11 #include <mythtv/mythdbcon.h> 12 12 13 13 #include "metadata.h" 14 #include "treebuilders.h" 14 15 15 struct FieldSplitInfo {16 QString testStr;17 QString dispStr;18 };19 20 static FieldSplitInfo splitArray4[] =21 {22 {"ABCDE", " (A B C D E)"},23 {"FGHIJ", " (F G H I J)"},24 {"KLMNO", " (K L M N O)"},25 {"PQRST", " (P Q R S T)"},26 {"UVWXYZ", " (U V W X Y Z)"}27 };28 const int kSplitArray4_Max = sizeof splitArray4 / sizeof splitArray4[0];29 30 static FieldSplitInfo splitArray1[] =31 {32 {"A", " (A)"},33 {"B", " (B)"},34 {"C", " (C)"},35 {"D", " (D)"},36 {"E", " (E)"},37 {"F", " (F)"},38 {"G", " (G)"},39 {"H", " (H)"},40 {"I", " (I)"},41 {"J", " (J)"},42 {"K", " (K)"},43 {"L", " (L)"},44 {"M", " (M)"},45 {"N", " (N)"},46 {"O", " (O)"},47 {"P", " (P)"},48 {"Q", " (Q)"},49 {"R", " (R)"},50 {"S", " (S)"},51 {"T", " (T)"},52 {"U", " (U)"},53 {"V", " (V)"},54 {"W", " (W)"},55 {"X", " (X)"},56 {"Y", " (Y)"},57 {"Z", " (Z)"},58 };59 const int kSplitArray1_Max = sizeof splitArray1 / sizeof splitArray1[0];60 61 16 static QString thePrefix = "the "; 62 17 63 18 bool operator==(const Metadata& a, const Metadata& b) … … 454 405 } 455 406 } 456 407 457 bool Metadata::areYouFinished(uint depth, uint treedepth, const QString &paths)458 {459 if(paths == "directory")460 {461 // have we made it to directory just above the file name?462 463 QString working = filename;464 working.replace(QRegExp(m_startdir), QString(""));465 working = working.section('/', depth);466 if(working.contains('/') < 1)467 {468 return true;469 }470 }471 else472 {473 if(depth + 1 >= treedepth)474 {475 return true;476 }477 }478 return false;479 }480 481 void Metadata::getField(const QStringList &tree_levels, QString *data, const QString &paths, uint depth)482 {483 if(paths == "directory")484 {485 // Return directory values as if they were486 // real metadata/TAG values487 488 QString working = filename;489 working.replace(QRegExp(m_startdir), QString(""));490 working.replace(QRegExp("/[^/]*$"), QString(""));491 492 working = working.section('/', depth, depth);493 494 *data = working;495 }496 else497 {498 getField(tree_levels[depth], data);499 }500 }501 502 408 void Metadata::getField(const QString &field, QString *data) 503 409 { 504 410 if (field == "artist") … … 509 415 *data = FormatTitle(); 510 416 else if (field == "genre") 511 417 *data = genre; 512 else if (field == "splitartist")513 {514 bool set = false;515 QString firstchar;516 if (FormatArtist().left(4).lower() == thePrefix)517 firstchar = FormatArtist().mid(4, 1).upper();518 else519 firstchar = FormatArtist().left(1).upper();520 521 for (int i = 0; i < kSplitArray4_Max; i++)522 {523 if (splitArray4[i].testStr.contains(firstchar))524 {525 set = true;526 *data = QObject::tr("Artists") + splitArray4[i].dispStr;527 }528 }529 530 if (!set)531 *data = QObject::tr("Artists") + " (" + firstchar + ")";532 }533 else if (field == "splitartist1")534 {535 bool set = false;536 QString firstchar;537 if (FormatArtist().left(4).lower() == thePrefix)538 firstchar = FormatArtist().mid(4, 1).upper();539 else540 firstchar = FormatArtist().left(1).upper();541 542 for (int i = 0; i < kSplitArray1_Max; i++)543 {544 if (splitArray1[i].testStr.contains(firstchar))545 {546 set = true;547 *data = QObject::tr("Artists") + splitArray1[i].dispStr;548 }549 }550 551 if (!set)552 *data = QObject::tr("Artists") + " (" + firstchar + ")";553 }554 418 else 555 419 { 556 420 cerr << "metadata.o: Something asked me to return data about a field called " << field << endl ; … … 942 786 numLoaded++; 943 787 } 944 788 945 intoTree(list); 789 MusicTreeBuilder *builder = MusicTreeBuilder::createBuilder (paths); 790 builder->makeTree (root_node, list); 791 delete builder; 946 792 } 947 793 948 794 void AllMusic::writeTree(GenericTree *tree_to_write_to) 949 795 { 950 796 root_node->writeTree(tree_to_write_to, 0); 951 797 } 952 798 953 799 bool AllMusic::putYourselfOnTheListView(TreeCheckItem *where) 954 800 { 955 801 root_node->putYourselfOnTheListView(where, false); 956 802 return true; 957 803 } 958 804 959 805 void AllMusic::putCDOnTheListView(CDCheckItem *where) … … 1041 824 } 1042 825 } 1043 826 1044 1045 void AllMusic::intoTree(QPtrList<Metadata> &list)1046 {1047 uint depth = 0;1048 QString a_field = "";1049 1050 QDict<MetadataPtrList> mapping;1051 QPtrListIterator<Metadata> iter( list );1052 MetadataPtrList *curList;1053 mapping.setAutoDelete(true);1054 1055 Metadata *cur;1056 while ((cur = iter.current()) != 0)1057 {1058 if (cur->areYouFinished(depth, tree_levels.count(), paths, m_startdir))1059 {1060 // special case, track is at root level1061 // e.g. an mp3 in the root directory and1062 // paths=directory1063 root_node->insert(cur);1064 ++iter;1065 continue;1066 }1067 1068 cur->getField(tree_levels.first(), &a_field, paths, m_startdir, depth);1069 curList = mapping.find(a_field);1070 if (!curList)1071 {1072 curList = new MetadataPtrList;1073 mapping.insert(a_field, curList);1074 }1075 curList->append(cur);1076 ++iter;1077 }1078 1079 QDictIterator<MetadataPtrList> rest(mapping);1080 while ((curList = rest.current()) != 0)1081 {1082 a_field = rest.currentKey();1083 MusicNode *new_one = new MusicNode(a_field, tree_levels, 0);1084 top_nodes.append(new_one);1085 new_one->intoTree(tree_levels, *curList, depth + 1);1086 ++rest;1087 }1088 }1089 1090 827 QString AllMusic::getLabel(int an_id, bool *error_flag) 1091 828 { 1092 829 QString a_label = ""; … … 1232 969 1233 970 // Error checking 971 QStringList tree_levels = QStringList::split(" ", paths); 1234 972 QStringList::const_iterator it = tree_levels.begin(); 1235 973 for (; it != tree_levels.end(); ++it) 1236 974 { … … 1265 1003 } 1266 1004 } 1267 1005 1268 MusicNode::MusicNode( QString a_title, QStringList tree_levels, uint depth)1006 MusicNode::MusicNode(const QString &a_title, const QString &tree_level) 1269 1007 { 1270 1008 my_title = a_title; 1271 if (m_paths == "directory") 1272 { 1273 my_level = "directory"; 1274 } 1275 else 1276 { 1277 if (depth < tree_levels.count()) 1278 my_level = tree_levels[depth]; 1279 else 1280 { 1281 my_level = "I am confused"; 1282 cerr << "metadata.o: Something asked me to look up a StringList entry that doesn't exist" << endl ; 1283 } 1284 1285 } 1286 1009 my_level = tree_level; 1287 1010 my_subnodes.setAutoDelete(true); 1288 1011 } 1289 1012 1290 1013 MusicNode::~MusicNode() … … 1311 1038 m_RandomWeight = gContext->GetNumSetting("IntelliRandomWeight", 2); 1312 1039 } 1313 1040 1314 void MusicNode::insert(Metadata* inserter)1315 {1316 my_tracks.append(inserter);1317 }1318 1319 void MusicNode::intoTree(QStringList tree_levels,1320 MetadataPtrList &list, uint depth)1321 {1322 QString a_field = "";1323 QString a_lowercase_field = "";1324 QString a_title = "";1325 bool usesPath = false;1326 1327 if (m_paths == "directory")1328 usesPath = true;1329 else1330 {1331 if (depth + 1 >= tree_levels.count())1332 {1333 my_tracks = list;1334 return;1335 }1336 }1337 1338 // Search and create from my node downards1339 1340 QDict<MetadataPtrList> mapping;1341 QPtrListIterator<Metadata> iter(list);1342 MetadataPtrList *curList;1343 mapping.setAutoDelete(true);1344 1345 Metadata *cur;1346 while ((cur = iter.current()) != 0)1347 {1348 if (usesPath && cur->areYouFinished(depth, tree_levels.count(), m_paths, m_startdir))1349 {1350 insert(cur);1351 ++iter;1352 continue;1353 }1354 1355 cur->getField(tree_levels, &a_field, m_paths, m_startdir, depth);1356 1357 a_lowercase_field = a_field.lower();1358 if (a_lowercase_field.left(4) == "the ")1359 a_field = a_field.mid(4);1360 1361 curList = mapping.find(a_field);1362 if (!curList)1363 {1364 curList = new MetadataPtrList;1365 mapping.insert(a_field, curList);1366 }1367 curList->append(cur);1368 ++iter;1369 }1370 1371 QDictIterator<MetadataPtrList> rest(mapping);1372 while ((curList = rest.current()) != 0)1373 {1374 a_field = rest.currentKey();1375 MusicNode *new_one = new MusicNode(a_field, tree_levels, depth);1376 my_subnodes.append(new_one);1377 new_one->intoTree(tree_levels, *curList, depth + 1);1378 ++rest;1379 }1380 }1381 1382 1041 void MusicNode::putYourselfOnTheListView(TreeCheckItem *parent, bool show_node) 1383 1042 { 1384 1043 TreeCheckItem *current_parent; -
mythmusic/mythmusic/metadata.h
126 126 void updateDatabase(void); 127 127 void setField(const QString &field, const QString &data); 128 void getField(const QString &field, QString *data); 129 void getField(const QStringList& tree_levels, QString *data, const QString &paths, const QString &startdir, uint depth); 130 bool areYouFinished(uint depth, uint treedepth, const QString& paths, const QString& startdir); 128 void getField(const QString& field, QString *data); 131 129 void fillData(); 132 130 void fillDataFromID(); 133 131 void persist(); … … 209 207 }; 210 208 211 209 class MusicNode 212 { 213 // Not a root of the music tree, and 214 // not a leaf, but anything in the 215 // middle 216 210 { 217 211 public: 218 212 219 MusicNode( QString a_title, QStringList tree_levels, uint depth);213 MusicNode(const QString &a_title, const QString &tree_level); 220 214 ~MusicNode(); 221 215 222 void insert(Metadata* inserter);223 216 QString getTitle(){return my_title;} 224 void intoTree(QStringList tree_levels, MetadataPtrList &list,225 uint depth);226 217 void printYourself(int indent_amount); // debugging 227 void clearTracks() { my_tracks.clear(); }228 218 void putYourselfOnTheListView(TreeCheckItem *parent, bool show_node); 229 219 void writeTree(GenericTree *tree_to_write_to, int a_counter); 230 220 void sort(); … … 233 223 void setLastPlayMin(double tmp_min) { lastplayMin = tmp_min; } 234 224 void setLastPlayMax(double tmp_max) { lastplayMax = tmp_max; } 235 225 226 inline void addChild(MusicNode *child) { my_subnodes.append(child); } 227 inline void addLeaf(Metadata *leaf) { my_tracks.append(leaf); } 228 inline void setLeaves(MetadataPtrList leaves) { my_tracks = leaves; } 229 230 void clear(void) { 231 my_tracks.clear(); 232 my_subnodes.clear(); 233 } 234 236 235 static void SetStaticData(const QString &startdir, const QString &paths); 237 236 238 237 private: 239 238 240 239 MetadataPtrList my_tracks; 241 240 MusicNodePtrList my_subnodes; 242 QDict<MusicNode> my_subnode_hash;243 241 QString my_title; 244 242 QString my_level; 245 243 … … 297 295 void printTree(); // debugging 298 296 void sortTree(); 299 297 void writeTree(GenericTree *tree_to_write_to); 300 void intoTree(QPtrList<Metadata> &list);301 298 void setSorting(QString a_paths); 302 bool putYourselfOnTheListView(TreeCheckItem *where , int how_many);299 bool putYourselfOnTheListView(TreeCheckItem *where); 303 300 void putCDOnTheListView(CDCheckItem *where); 304 301 bool doneLoading(){return done_loading;} 305 302 bool cleanOutThreads(); … … 330 326 331 327 QString startdir; 332 328 QString paths; 333 QStringList tree_levels;334 329 335 330 336 331 MetadataLoadingThread *metadata_loader; -
mythmusic/mythmusic/databasebox.cpp
189 189 the_playlists->doneLoading()) 190 190 { 191 191 // Good, now lets grab some QListItems 192 // 193 // Say ... I dunno ... 100 at a time? 194 195 if (all_music->putYourselfOnTheListView(allmusic, 100)) 192 if (all_music->putYourselfOnTheListView(allmusic)) 196 193 { 197 194 allmusic->setText(tr("All My Music")); 198 195 fill_list_timer->stop(); -
mythmusic/mythmusic/treebuilders.h
1 #ifndef TREEBUILDERS_H_ 2 #define TREEBUILDERS_H_ 3 4 #include <qstring.h> 5 #include <qstringlist.h> 6 #include <qptrdict.h> 7 #include <qdict.h> 8 9 #include "metadata.h" 10 11 /** \class MusicTreeBuilder 12 \brief superclass for the objects that build trees of \p Metadata 13 14 This is the interface for objects that builds trees of \p Metadata 15 objects into \p MusicNode objects. 16 17 The basic idea of operation is, that the superclass provices a 18 makeTree method that depends on the subclasses for a few methods 19 to determine which fields of the metadata objects are used in 20 building the tree and where the metadata objects go. 21 22 This means that the superclass is fairly generic and does not 23 itself operate on or query the metadata objects, but leaves that 24 to the subclass. It's only responsibility is to determine the 25 branches that go into the tree and then add metadata objects as 26 leafs to the appropriate nodes. 27 28 Ie. if you wanted to build the MythMusic tree based on the size of 29 the audio files by implementing a \p MusicSizeTreeBuilder, the 30 approach would be to get \p MusicSizeTreeBuilder::getField return 31 the number of MB or KB blocks depending on the current depth as 32 obtained by \p getDept. Then you could either overload \p makeTree 33 to stop at a certain depth (like \p MusicFieldBuilder does) or 34 make \p MusicSizeTreeBuilder::isLeafDone return true if you've 35 reached the desired granularity. 36 37 \note This method is fairly generic, and uses very little of the 38 interfaces of \p MusicNode and \p Metadata, so it may someday be 39 made more generic and of use to other plugins that needs trees. 40 41 \note Calling this repeated using the same or new instance on the 42 same root node (ie. to progressively populate it) hasn't been 43 tested. 44 */ 45 class MusicTreeBuilder 46 { 47 public: 48 virtual ~MusicTreeBuilder(); 49 50 /** \fn Create a tree using the list of \p Metadata objects and add them to the given root. 51 52 This method will recurse and operate of the list the metadata 53 objects in \p metas. It's implementation may and probably will 54 differ depending on the subclass of builder you've obtained, 55 depending on the kind of tree it builds. 56 57 It relies heavily on subclasses implementing \p 58 MusicTreeBuilder::isLeafDone and \p MusicTreeBuilder::getField 59 for operation, and for performance, the subclasses should 60 cache computed data in these methods as efficiently as possible. 61 */ 62 virtual void makeTree(MusicNode *root, const MetadataPtrList &metas); 63 64 /** \fn Create an \p MusicTreeBuilder for the appropriate path. 65 66 Returns a \p MusicTreeBuilder subclass for building directory 67 based or "artist album" field based trees. 68 */ 69 static MusicTreeBuilder *createBuilder(const QString &paths); 70 71 protected: 72 MusicTreeBuilder(); 73 74 /** \fn Allocates and returns a new \p MusicNode. 75 76 Implemented by the subclass. This method should allocate and a 77 return a \p MusicNode with the approriate "level" set. 78 */ 79 virtual MusicNode *createNode(const QString &title) = 0; 80 81 /** \fn Determine is a \p Metadata should be track at the current depth. 82 83 Ie. the directory builder will return true if the given \p 84 Metadata's path at the current depth is the filename. 85 86 Gets called repeatedly from \p MusicTreeBuilder::makeTree 87 during tree creation and should only get called once 88 pr. depth pr. \p Metadata. 89 */ 90 virtual bool isLeafDone(Metadata *m) = 0; 91 92 /** \fn Get the field value for the given \p Metadata at the current depth. 93 94 Ie. the field builder will call \p Metadata::getField with 95 the appropriate field name for the current dept. 96 97 Gets called repeatedly from \p MusicTreeBuilder::makeTree 98 during tree creation and may get called multiple times at the 99 same depth for the same \p Metadata. 100 */ 101 virtual QString getField(Metadata *m) = 0; 102 103 /** \fn Get the current depth during tree building. 104 105 While \p MusicTreeBuilder::makeTree is recursing downwards to 106 build the tree, this method will return the current depth and 107 can/should be used in the subclass when implemented the 108 virtual methods. 109 110 Ie. the directory builder can use this in isLeafDone to 111 determine if the \p Metadata object under consideration has no 112 more elements in it's path. 113 */ 114 inline int getDepth(void) { return m_depth; } 115 116 private: 117 int m_depth; 118 }; 119 120 #endif /* TREEBUILDERS_H_ */ -
mythmusic/mythmusic/treebuilders.cpp
1 #include <mythtv/mythcontext.h> 2 #include "treebuilders.h" 3 4 typedef struct { 5 QString field; 6 MetadataPtrList list; 7 } Branch; 8 9 typedef struct { 10 QString testStr; 11 QString dispStr; 12 } FieldSplitInfo; 13 14 static FieldSplitInfo splitArray4[] = 15 { 16 {"!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~", " (...)"}, 17 {"01234", " (0 1 2 3 4)" }, 18 {"56789", " (5 6 7 8 9)" }, 19 {"ABCDE", " (A B C D E)"}, 20 {"FGHIJ", " (F G H I J)"}, 21 {"KLMNO", " (K L M N O)"}, 22 {"PQRST", " (P Q R S T)"}, 23 {"UVWXYZ", " (U V W X Y Z)"} 24 }; 25 const int kSplitArray4_Max = sizeof splitArray4 / sizeof splitArray4[0]; 26 27 static QString thePrefix = "the "; 28 29 MusicTreeBuilder::MusicTreeBuilder() 30 { 31 m_depth = -1; 32 } 33 34 MusicTreeBuilder::~MusicTreeBuilder() 35 { 36 } 37 38 void MusicTreeBuilder::makeTree(MusicNode *root, const MetadataPtrList &metas) 39 { 40 m_depth++; 41 42 typedef QMap<QString, Branch*> BranchMap; 43 BranchMap branches; 44 45 Metadata *meta; 46 QPtrListIterator<Metadata> iter(metas); 47 while ((meta = iter.current()) != 0) 48 { 49 if (isLeafDone(meta)) 50 { 51 root->addLeaf(meta); 52 } 53 else 54 { 55 QString field = getField(meta); 56 QString field_key = field.lower(); 57 58 if (field_key.left(4) == thePrefix) 59 field_key = field_key.mid(4); 60 61 Branch *branch = branches[field_key]; 62 if (branch == NULL) 63 { 64 branch = new Branch; 65 branch->field = field; 66 branches[field_key] = branch; 67 } 68 branch->list.append(meta); 69 } 70 71 ++iter; 72 } 73 74 for(BranchMap::iterator it = branches.begin(); it != branches.end(); it++) 75 { 76 Branch *branch = it.data(); 77 MusicNode *sub_node = createNode(branch->field); 78 root->addChild(sub_node); 79 makeTree(sub_node, branch->list); 80 delete branch; 81 } 82 83 m_depth--; 84 } 85 86 class MusicFieldTreeBuilder : public MusicTreeBuilder 87 { 88 public: 89 MusicFieldTreeBuilder(const QString &paths) 90 { 91 m_paths = QStringList::split(' ', paths); 92 } 93 94 ~MusicFieldTreeBuilder() 95 { 96 } 97 98 void makeTree(MusicNode *root, const MetadataPtrList &metas) 99 { 100 if ((uint)getDepth() + 2 >= m_paths.size()) 101 { 102 root->setLeaves(metas); 103 return; 104 } 105 106 MusicTreeBuilder::makeTree(root, metas); 107 } 108 109 protected: 110 MusicNode *createNode(const QString &title) 111 { 112 return new MusicNode(title, m_paths[getDepth()]); 113 } 114 115 bool isLeafDone(Metadata *) 116 { 117 return false; 118 } 119 120 QString getField(Metadata *meta) 121 { 122 QString field = m_paths[getDepth()]; 123 124 if (field == "splitartist1" || 125 field == "splitartist") 126 { 127 return getSplitField(meta, field); 128 } 129 130 QString data; 131 meta->getField(field, &data); 132 return data; 133 } 134 135 private: 136 QStringList m_paths; 137 //QDict<QString> m_charToSplitMap; 138 QMap<QChar, QString> m_split_map; 139 140 QString getSplitField(Metadata *meta, const QString &field) 141 { 142 QString firstchar_str = meta->FormatArtist().stripWhiteSpace(); 143 144 if (firstchar_str.left(4).lower() == thePrefix) 145 firstchar_str = firstchar_str.mid(4,1).upper(); 146 else 147 firstchar_str = firstchar_str.left(1).upper(); 148 149 QChar firstchar = firstchar_str[0]; 150 QString split = m_split_map[firstchar]; 151 152 if (split.isEmpty()) 153 { 154 if (field == "splitartist1") 155 { 156 split = QObject::tr("Artists ") + "(" + firstchar + ")"; 157 m_split_map[firstchar] = split; 158 } 159 else 160 { 161 int split_max = kSplitArray4_Max; 162 FieldSplitInfo *splits = splitArray4; 163 164 for(int i = 0; i < split_max; i++) 165 { 166 if (splits[i].testStr.contains(firstchar)) 167 { 168 split = QObject::tr("Artists ") + splits[i].dispStr; 169 m_split_map[firstchar] = split; 170 break; 171 } 172 } 173 } 174 } 175 176 if (split.isEmpty()) 177 { 178 split = QObject::tr("Artists") + "(" + firstchar + ")"; 179 m_split_map[firstchar] = split; 180 } 181 182 return split; 183 } 184 }; 185 186 class MusicDirectoryTreeBuilder : public MusicTreeBuilder 187 { 188 public: 189 MusicDirectoryTreeBuilder() 190 { 191 m_startdir = gContext->GetSetting("MusicLocation"); 192 } 193 194 ~MusicDirectoryTreeBuilder() 195 { 196 for(MetaMap::iterator it = m_map.begin(); it != m_map.end(); it++) 197 delete it.data(); 198 } 199 200 protected: 201 MusicNode *createNode(const QString &title) 202 { 203 return new MusicNode(title, "directory"); 204 } 205 206 bool isLeafDone(Metadata *meta) 207 { 208 return(uint)getDepth() + 1 >= getPathsForMeta(meta)->size(); 209 } 210 211 QString getField(Metadata *meta) 212 { 213 return getPathsForMeta(meta)->operator[](getDepth()); 214 } 215 216 private: 217 inline QString getStartdir(void) { return m_startdir; } 218 219 QStringList* getPathsForMeta(Metadata *meta) 220 { 221 QStringList *paths = m_map[meta]; 222 223 if (paths) 224 return paths; 225 226 QString filename = meta->Filename().remove(0, getStartdir().length()); 227 paths = new QStringList(QStringList::split('/', filename)); 228 m_map[meta] = paths; 229 230 return paths; 231 } 232 233 typedef QMap<Metadata*,QStringList*> MetaMap; 234 MetaMap m_map; 235 QString m_startdir; 236 237 }; 238 239 MusicTreeBuilder *MusicTreeBuilder::createBuilder(const QString &paths) 240 { 241 if (paths == "directory") 242 return new MusicDirectoryTreeBuilder(); 243 244 return new MusicFieldTreeBuilder(paths); 245 } 246