plugin code
[lbook_fbreader.git] / fbreader / src / collection / BookCollection.cpp
blobf7c0c744c80ef4abbc741209d0fedef5f69b88eb
1 /*
2 * Copyright (C) 2004-2008 Geometer Plus <contact@geometerplus.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
20 #include <queue>
21 #include <algorithm>
23 #include <ZLibrary.h>
24 #include <ZLStringUtil.h>
25 #include <ZLFile.h>
26 #include <ZLDir.h>
28 #include "BookCollection.h"
29 #include "BookList.h"
30 #include "../description/BookDescription.h"
31 #include "../description/BookDescriptionUtil.h"
32 #include "../description/Author.h"
33 #include "../formats/FormatPlugin.h"
35 bool DescriptionComparator::operator() (const BookDescriptionPtr d1, const BookDescriptionPtr d2) {
36 const std::string &sequenceName1 = d1->sequenceName();
37 const std::string &sequenceName2 = d2->sequenceName();
38 if (sequenceName1.empty() && sequenceName2.empty()) {
39 return d1->title() < d2->title();
41 if (sequenceName1.empty()) {
42 return d1->title() < sequenceName2;
44 if (sequenceName2.empty()) {
45 return sequenceName1 <= d2->title();
47 if (sequenceName1 != sequenceName2) {
48 return sequenceName1 < sequenceName2;
50 return d1->numberInSequence() < d2->numberInSequence();
53 static const std::string OPTIONS = "Options";
55 BookCollection::BookCollection() :
56 PathOption(ZLCategoryKey::CONFIG, OPTIONS, "BookPath", ""),
57 ScanSubdirsOption(ZLCategoryKey::CONFIG, OPTIONS, "ScanSubdirs", false),
58 myDoStrongRebuild(true),
59 myDoWeakRebuild(false) {
62 void BookCollection::rebuild(bool strong) {
63 if (strong) {
64 myDoStrongRebuild = true;
65 } else {
66 myDoWeakRebuild = true;
70 void BookCollection::collectBookFileNames(std::set<std::string> &bookFileNames) const {
71 std::set<std::string> dirs;
72 collectDirNames(dirs);
74 for (std::set<std::string>::iterator it = dirs.begin(); it != dirs.end(); ++it) {
75 std::vector<std::string> files;
76 shared_ptr<ZLDir> dir = ZLFile(*it).directory();
77 if (dir.isNull()) {
78 continue;
80 dir->collectFiles(files, false);
81 if (!files.empty()) {
82 for (std::vector<std::string>::const_iterator jt = files.begin(); jt != files.end(); ++jt) {
83 const std::string fileName = dir->itemPath(*jt);
84 ZLFile file(fileName);
85 if (PluginCollection::instance().plugin(file, true) != 0) {
86 bookFileNames.insert(fileName);
87 // TODO: zip -> any archive
88 } else if (file.extension() == "zip") {
89 if (!BookDescriptionUtil::checkInfo(file)) {
90 BookDescriptionUtil::resetZipInfo(file);
91 BookDescriptionUtil::saveInfo(file);
93 std::vector<std::string> zipEntries;
94 BookDescriptionUtil::listZipEntries(file, zipEntries);
95 for (std::vector<std::string>::const_iterator zit = zipEntries.begin(); zit != zipEntries.end(); ++zit) {
96 bookFileNames.insert(*zit);
104 bool BookCollection::synchronize() const {
105 bool doStrongRebuild =
106 myDoStrongRebuild ||
107 (myScanSubdirs != ScanSubdirsOption.value()) ||
108 (myPath != PathOption.value());
110 if (!doStrongRebuild && !myDoWeakRebuild) {
111 return false;
114 myPath = PathOption.value();
115 myScanSubdirs = ScanSubdirsOption.value();
116 myDoWeakRebuild = false;
117 myDoStrongRebuild = false;
119 if (doStrongRebuild) {
120 myAuthors.clear();
121 myCollection.clear();
122 myExternalBooks.clear();
124 std::set<std::string> fileNamesSet;
125 collectBookFileNames(fileNamesSet);
126 for (std::set<std::string>::iterator it = fileNamesSet.begin(); it != fileNamesSet.end(); ++it) {
127 addDescription(BookDescription::getDescription(*it));
130 BookList bookList;
131 const std::set<std::string> &bookListSet = bookList.fileNames();
132 for (std::set<std::string>::const_iterator it = bookListSet.begin(); it != bookListSet.end(); ++it) {
133 if (fileNamesSet.find(*it) == fileNamesSet.end()) {
134 BookDescriptionPtr description = BookDescription::getDescription(*it);
135 if (!description.isNull()) {
136 addDescription(description);
137 myExternalBooks.insert(description);
141 } else {
142 BookList bookList;
143 const std::set<std::string> &bookListSet = bookList.fileNames();
144 std::vector<std::string> fileNames;
145 for (std::map<AuthorPtr,Books>::const_iterator it = myCollection.begin(); it != myCollection.end(); ++it) {
146 const Books &books = it->second;
147 for (Books::const_iterator jt = books.begin(); jt != books.end(); ++jt) {
148 if ((myExternalBooks.find(*jt) == myExternalBooks.end()) ||
149 (bookListSet.find((*jt)->fileName()) != bookListSet.end())) {
150 fileNames.push_back((*jt)->fileName());
154 myCollection.clear();
155 myAuthors.clear();
156 for (std::vector<std::string>::iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
157 addDescription(BookDescription::getDescription(*it, false));
161 std::sort(myAuthors.begin(), myAuthors.end(), AuthorComparator());
162 DescriptionComparator descriptionComparator;
163 for (std::map<AuthorPtr,Books>::iterator it = myCollection.begin(); it != myCollection.end(); ++it) {
164 std::sort((*it).second.begin(), (*it).second.end(), descriptionComparator);
166 return true;
169 void BookCollection::collectDirNames(std::set<std::string> &nameSet) const {
170 std::queue<std::string> nameQueue;
172 std::string path = myPath;
173 int pos = path.find(ZLibrary::PathDelimiter);
174 while (pos != -1) {
175 nameQueue.push(path.substr(0, pos));
176 path.erase(0, pos + 1);
177 pos = path.find(ZLibrary::PathDelimiter);
179 if (!path.empty()) {
180 nameQueue.push(path);
183 while (!nameQueue.empty()) {
184 std::string name = nameQueue.front();
185 nameQueue.pop();
186 if (nameSet.find(name) == nameSet.end()) {
187 if (myScanSubdirs) {
188 shared_ptr<ZLDir> dir = ZLFile(name).directory();
189 if (!dir.isNull()) {
190 std::vector<std::string> subdirs;
191 dir->collectSubDirs(subdirs, false);
192 for (std::vector<std::string>::const_iterator it = subdirs.begin(); it != subdirs.end(); ++it) {
193 nameQueue.push(dir->itemPath(*it));
197 nameSet.insert(name);
202 BookCollection::~BookCollection() {
205 void BookCollection::addDescription(BookDescriptionPtr description) const {
206 if (description.isNull()) {
207 return;
210 AuthorPtr author = description->author();
211 const std::string &displayName = author->displayName();
212 const std::string &sortKey = author->sortKey();
214 std::map<AuthorPtr,Books>::iterator it = myCollection.begin();
215 for (; it != myCollection.end(); ++it) {
216 AuthorPtr author1 = (*it).first;
217 if ((author1->sortKey() == sortKey) && (author1->displayName() == displayName)) {
218 break;
221 if (it != myCollection.end()) {
222 (*it).second.push_back(description);
223 } else {
224 Books books;
225 books.push_back(description);
226 myCollection.insert(std::pair<AuthorPtr,Books>(author, books));
227 myAuthors.push_back(author);