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
24 #include <ZLStringUtil.h>
28 #include "BookCollection.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
) {
64 myDoStrongRebuild
= true;
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();
80 dir
->collectFiles(files
, false);
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
=
107 (myScanSubdirs
!= ScanSubdirsOption
.value()) ||
108 (myPath
!= PathOption
.value());
110 if (!doStrongRebuild
&& !myDoWeakRebuild
) {
114 myPath
= PathOption
.value();
115 myScanSubdirs
= ScanSubdirsOption
.value();
116 myDoWeakRebuild
= false;
117 myDoStrongRebuild
= false;
119 if (doStrongRebuild
) {
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
));
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
);
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();
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
);
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
);
175 nameQueue
.push(path
.substr(0, pos
));
176 path
.erase(0, pos
+ 1);
177 pos
= path
.find(ZLibrary::PathDelimiter
);
180 nameQueue
.push(path
);
183 while (!nameQueue
.empty()) {
184 std::string name
= nameQueue
.front();
186 if (nameSet
.find(name
) == nameSet
.end()) {
188 shared_ptr
<ZLDir
> dir
= ZLFile(name
).directory();
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()) {
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
)) {
221 if (it
!= myCollection
.end()) {
222 (*it
).second
.push_back(description
);
225 books
.push_back(description
);
226 myCollection
.insert(std::pair
<AuthorPtr
,Books
>(author
, books
));
227 myAuthors
.push_back(author
);