diff options
Diffstat (limited to 'reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp')
-rw-r--r-- | reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp b/reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp new file mode 100644 index 0000000..197bd98 --- /dev/null +++ b/reader/src/optionsDialog/bookInfo/BookInfoDialog.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <algorithm> + +#include <ZLDialogManager.h> +#include <ZLOptionsDialog.h> +#include <ZLOptionEntry.h> +#include <ZLFile.h> +#include <ZLLanguageList.h> +#include <ZLStringUtil.h> + +#include <ZLStringInfoEntry.h> +#include <ZLSimpleOptionEntry.h> +#include <ZLLanguageOptionEntry.h> + +#include "BookInfoDialog.h" + +#include "../../library/Library.h" +#include "../../encodingOption/EncodingOptionEntry.h" +#include "../../library/Book.h" +#include "../../library/Tag.h" +#include "../../library/Author.h" + +static const std::size_t AUTHOR_ENTRIES_POOL_SIZE = 64; +static const std::size_t TAG_ENTRIES_POOL_SIZE = 64; + +class AuthorDisplayNameEntry : public ZLComboOptionEntry { + +public: + AuthorDisplayNameEntry(BookInfoDialog &dialog, shared_ptr<Author> initialAuthor, bool &visible); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + + bool useOnValueEdited() const; + void onValueEdited(const std::string &value); + void onValueSelected(int index); + +private: + void onValueChanged(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; + mutable std::vector<std::string> myValues; + shared_ptr<Author> myCurrentAuthor; + + std::string myInitialValue; + bool myEmpty; + +friend class SeriesTitleEntry; +friend class BookInfoApplyAction; +}; + + +class SeriesTitleEntry : public ZLComboOptionEntry { + +public: + SeriesTitleEntry(BookInfoDialog &dialog); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + + bool useOnValueEdited() const; + void onValueEdited(const std::string &value); + void onValueSelected(int index); + +private: + BookInfoDialog &myInfoDialog; + std::set<std::string> myOriginalValuesSet; + mutable std::vector<std::string> myValues; +}; + + +class BookIndexEntry : public ZLStringOptionEntry { + +public: + BookIndexEntry(BookInfoDialog &dialog); + + const std::string &initialValue() const; + void onAccept(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; +}; + + + + +AuthorDisplayNameEntry::AuthorDisplayNameEntry(BookInfoDialog &dialog, shared_ptr<Author> initialAuthor, bool &visible) : + ZLComboOptionEntry(true), myInfoDialog(dialog), myCurrentAuthor(initialAuthor) { + + if (myCurrentAuthor.isNull()) { + myInitialValue = ""; + myEmpty = true; + } else { + myInitialValue = myCurrentAuthor->name(); + myEmpty = myInitialValue.empty(); + } + setVisible(visible || !myEmpty); + if (visible && myEmpty) { + visible = false; + } +} + +const std::string &AuthorDisplayNameEntry::initialValue() const { + return myInitialValue; +} + +const std::vector<std::string> &AuthorDisplayNameEntry::values() const { + if (myValues.empty()) { + const std::string &initial = initialValue(); + bool addInitial = true; + const AuthorList &authors = Library::Instance().authors(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + if (it->isNull()) { + continue; + } + const std::string name = (*it)->name(); + if (addInitial && (name == initial)) { + addInitial = false; + } + myValues.push_back(name); + } + if (addInitial) { + myValues.push_back(initial); + } + } + return myValues; +} + +void AuthorDisplayNameEntry::onAccept(const std::string &value) { + if (!isVisible() || value.empty()) { + myCurrentAuthor = 0; + return; + } + if (!myCurrentAuthor.isNull() && value == myCurrentAuthor->name()) { + //myCurrentAuthor = myCurrentAuthor; + return; + } + myCurrentAuthor = Author::getAuthor(value); +} + + +bool AuthorDisplayNameEntry::useOnValueEdited() const { + return true; +} + +void AuthorDisplayNameEntry::onValueEdited(const std::string &value) { + onValueChanged(value); +} + +void AuthorDisplayNameEntry::onValueSelected(int index) { + const AuthorList &authors = Library::Instance().authors(); + myCurrentAuthor = (((std::size_t)index) < authors.size()) ? authors[index] : 0; + myInfoDialog.mySeriesTitleEntry->resetView(); + onValueChanged(myValues[index]); +} + +void AuthorDisplayNameEntry::onValueChanged(const std::string &value) { + if (!myInfoDialog.myAuthorsDone || !isVisible()) { + return; + } + + myEmpty = value.empty(); + if (myEmpty) { + for (std::size_t i = 0; i < myInfoDialog.myAuthorEntries.size(); ++i) { + AuthorDisplayNameEntry &entry = *myInfoDialog.myAuthorEntries[i]; + if (entry.myEmpty && entry.isVisible() && this != &entry) { + entry.setVisible(false); + } + } + } else { + std::size_t i, lastvisible = (std::size_t) -1; + for (i = 0; i < myInfoDialog.myAuthorEntries.size(); ++i) { + AuthorDisplayNameEntry &entry = *myInfoDialog.myAuthorEntries[i]; + if (entry.isVisible()) { + lastvisible = i; + if (entry.myEmpty) { + break; + } + } + } + if (i == myInfoDialog.myAuthorEntries.size()) { + if (lastvisible + 1 < i) { + AuthorDisplayNameEntry &entry = *myInfoDialog.myAuthorEntries[lastvisible + 1]; + entry.setVisible(true); + } + // else pool is over + } + } +} + + + + +SeriesTitleEntry::SeriesTitleEntry(BookInfoDialog &dialog) : ZLComboOptionEntry(true), myInfoDialog(dialog) { + const AuthorList &authors = myInfoDialog.myBook->authors(); + myOriginalValuesSet.insert(initialValue()); + myOriginalValuesSet.insert(""); + const Library &library = Library::Instance(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + library.collectSeriesTitles(*it, myOriginalValuesSet); + } +} + +const std::string &SeriesTitleEntry::initialValue() const { + return myInfoDialog.myBook->seriesTitle(); +} + +const std::vector<std::string> &SeriesTitleEntry::values() const { + std::set<std::string> valuesSet(myOriginalValuesSet); + + const Library &library = Library::Instance(); + const AuthorList &authors = myInfoDialog.myBook->authors(); + for (std::vector<AuthorDisplayNameEntry*>::const_iterator it = myInfoDialog.myAuthorEntries.begin(); it != myInfoDialog.myAuthorEntries.end(); ++it) { + shared_ptr<Author> currentAuthor = (*it)->myCurrentAuthor; + if (!currentAuthor.isNull() && std::find(authors.begin(), authors.end(), currentAuthor) == authors.end()) { + library.collectSeriesTitles(currentAuthor, valuesSet); + } + } + + /*myValues.clear(); + for (std::set<std::string>::const_iterator it = valuesSet.begin(); it != valuesSet.end(); ++it) { + myValues.push_back(*it); + }*/ + myValues.assign(valuesSet.begin(), valuesSet.end()); + return myValues; +} + +void SeriesTitleEntry::onAccept(const std::string &value) { + Book &book = *myInfoDialog.myBook; + book.setSeries(value, book.indexInSeries()); +} + +void SeriesTitleEntry::onValueSelected(int index) { + myInfoDialog.myBookIndexEntry->setVisible(index != 0); +} + +bool SeriesTitleEntry::useOnValueEdited() const { + return true; +} + +void SeriesTitleEntry::onValueEdited(const std::string &value) { + myInfoDialog.myBookIndexEntry->setVisible(!value.empty()); +} + +BookIndexEntry::BookIndexEntry(BookInfoDialog &dialog) : myInfoDialog(dialog) { +} + +const std::string &BookIndexEntry::initialValue() const { + return myInfoDialog.myBook->indexInSeries().value(); +} + +void BookIndexEntry::onAccept(const std::string &value) { + Book &book = *myInfoDialog.myBook; + //TODO implement validation + book.setSeries(book.seriesTitle(), Number(value)); +} + +class BookTitleEntry : public ZLStringOptionEntry { + +public: + BookTitleEntry(BookInfoDialog &dialog); + + const std::string &initialValue() const; + void onAccept(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookTitleEntry::BookTitleEntry(BookInfoDialog &dialog) : myInfoDialog(dialog) { +} + +const std::string &BookTitleEntry::initialValue() const { + return myInfoDialog.myBook->title(); +} + +void BookTitleEntry::onAccept(const std::string &value) { + myInfoDialog.myBook->setTitle(value); +} + + + + + + +class BookEncodingEntry : public AbstractEncodingEntry { + +public: + BookEncodingEntry(BookInfoDialog &dialog); + + void onAcceptValue(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookEncodingEntry::BookEncodingEntry(BookInfoDialog &dialog) : + AbstractEncodingEntry(dialog.myBook->encoding()), + myInfoDialog(dialog) { +} + +void BookEncodingEntry::onAcceptValue(const std::string &value) { + myInfoDialog.myBook->setEncoding(value); +} + + + +class BookLanguageEntry : public ZLAbstractLanguageOptionEntry { + +public: + BookLanguageEntry(BookInfoDialog &dialog, const std::vector<std::string> &languageCodes); + + void onAcceptCode(const std::string &code); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookLanguageEntry::BookLanguageEntry(BookInfoDialog &dialog, const std::vector<std::string> &languageCodes) : + ZLAbstractLanguageOptionEntry(dialog.myBook->language(), languageCodes), + myInfoDialog(dialog) { +} + +void BookLanguageEntry::onAcceptCode(const std::string &code) { + myInfoDialog.myBook->setLanguage(code); +} + + + + + +class BookTagEntry : public ZLComboOptionEntry { + +public: + BookTagEntry(BookInfoDialog &dialog, std::string initialTag, bool &visible); + + const std::string &initialValue() const; + const std::vector<std::string> &values() const; + void onAccept(const std::string &value); + + bool useOnValueEdited() const; + void onValueEdited(const std::string &value); + void onValueSelected(int index); + +private: + void onValueChanged(const std::string &value); + +private: + BookInfoDialog &myInfoDialog; + std::string myInitialValue; + bool myEmpty; + + mutable std::vector<std::string> myValues; +}; + +BookTagEntry::BookTagEntry(BookInfoDialog &dialog, std::string initialTag, bool &visible) : + ZLComboOptionEntry(true), myInfoDialog(dialog), myInitialValue(initialTag) { + + myEmpty = myInitialValue.empty(); + setVisible(visible || !myEmpty); + if (visible && myEmpty) { + visible = false; + } +} + +const std::string &BookTagEntry::initialValue() const { + return myInitialValue; +} + +const std::vector<std::string> &BookTagEntry::values() const { + if (myValues.empty()) { + myValues.push_back(""); + Tag::collectTagNames(myValues); + } + return myValues; +} + +void BookTagEntry::onAccept(const std::string &value) { + if (isVisible() && !value.empty()) { + myInfoDialog.myNewTags.push_back(value); + } +} + +bool BookTagEntry::useOnValueEdited() const { + return true; +} + +void BookTagEntry::onValueEdited(const std::string &value) { + onValueChanged(value); +} + +void BookTagEntry::onValueSelected(int index) { + onValueChanged(myValues[index]); +} + +void BookTagEntry::onValueChanged(const std::string &value) { + if (!myInfoDialog.myTagsDone || !isVisible()) { + return; + } + + myEmpty = value.empty(); + if (myEmpty) { + for (std::size_t i = 0; i < myInfoDialog.myTagEntries.size(); ++i) { + BookTagEntry &entry = *myInfoDialog.myTagEntries[i]; + if (entry.myEmpty && entry.isVisible() && this != &entry) { + entry.setVisible(false); + } + } + } else { + std::size_t i, lastvisible = (std::size_t) -1; + for (i = 0; i < myInfoDialog.myTagEntries.size(); ++i) { + BookTagEntry &entry = *myInfoDialog.myTagEntries[i]; + if (entry.isVisible()) { + lastvisible = i; + if (entry.myEmpty) { + break; + } + } + } + if (i == myInfoDialog.myTagEntries.size()) { + if (lastvisible + 1 < i) { + BookTagEntry &entry = *myInfoDialog.myTagEntries[lastvisible + 1]; + entry.setVisible(true); + } + } + } +} + +class BookInfoApplyAction : public ZLRunnable { + +public: + BookInfoApplyAction(BookInfoDialog &dialog); + void run(); + +private: + BookInfoDialog &myInfoDialog; +}; + +BookInfoApplyAction::BookInfoApplyAction(BookInfoDialog &dialog) : myInfoDialog(dialog) {} + +void BookInfoApplyAction::run() { + Book &book = *myInfoDialog.myBook; + + AuthorList authors; + for (std::size_t i = 0; i < myInfoDialog.myAuthorEntries.size(); ++i) { + shared_ptr<Author> a = myInfoDialog.myAuthorEntries[i]->myCurrentAuthor; + if (!a.isNull() && + std::find(authors.begin(), authors.end(), a) == authors.end()) { + authors.push_back(a); + } + } + + book.removeAllAuthors(); + for (AuthorList::const_iterator it = authors.begin(); it != authors.end(); ++it) { + book.addAuthor(*it); + } + + book.removeAllTags(); + for (std::size_t i = 0; i < myInfoDialog.myNewTags.size(); ++i) { + book.addTag(myInfoDialog.myNewTags[i]); + } + + Library::Instance().updateBook(myInfoDialog.myBook); +} + +BookInfoDialog::BookInfoDialog(shared_ptr<Book> book) : myBook(book) { + myDialog = ZLDialogManager::Instance().createOptionsDialog(ZLResourceKey("InfoDialog"), new BookInfoApplyAction(*this)); + + ZLDialogContent &commonTab = myDialog->createTab(ZLResourceKey("Common")); + commonTab.addOption(ZLResourceKey("file"), + new ZLStringInfoEntry(ZLFile::fileNameToUtf8(book->file().path())) + ); + commonTab.addOption(ZLResourceKey("title"), new BookTitleEntry(*this)); + + myEncodingEntry = new BookEncodingEntry(*this); + myEncodingSetEntry = + (myEncodingEntry->initialValue() != Book::AutoEncoding) ? + new EncodingSetEntry(*(EncodingEntry*)myEncodingEntry) : 0; + std::vector<std::string> languageCodes = ZLLanguageList::languageCodes(); + languageCodes.push_back("de-traditional"); + myLanguageEntry = new BookLanguageEntry(*this, languageCodes); + mySeriesTitleEntry = new SeriesTitleEntry(*this); + myBookIndexEntry = new BookIndexEntry(*this); + + commonTab.addOption(ZLResourceKey("language"), myLanguageEntry); + if (myEncodingSetEntry != 0) { + commonTab.addOption(ZLResourceKey("encodingSet"), myEncodingSetEntry); + } + commonTab.addOption(ZLResourceKey("encoding"), myEncodingEntry); + + initAuthorEntries(); + + ZLDialogContent &seriesTab = myDialog->createTab(ZLResourceKey("Series")); + seriesTab.addOption(ZLResourceKey("seriesTitle"), mySeriesTitleEntry); + seriesTab.addOption(ZLResourceKey("bookIndex"), myBookIndexEntry); + + mySeriesTitleEntry->onValueEdited(mySeriesTitleEntry->initialValue()); + /* + ZLOrderOptionEntry *orderEntry = new ZLOrderOptionEntry(); + orderEntry->values().push_back("First"); + orderEntry->values().push_back("Second"); + orderEntry->values().push_back("Third"); + orderEntry->values().push_back("Fourth"); + orderEntry->values().push_back("Fifth"); + seriesTab.addOption(orderEntry); + */ + + initTagEntries(); + + shared_ptr<FormatPlugin> plugin = PluginCollection::Instance().plugin(*book); + if (!plugin.isNull()) { + myFormatInfoPage = plugin->createInfoPage(*myDialog, book->file()); + } +} + +void BookInfoDialog::initTagEntries() { + bool visible = true; + const TagList &tags = myBook->tags(); + myTagsDone = false; + myTagsTab = &myDialog->createTab(ZLResourceKey("Tags")); + for (std::size_t i = 0; i < TAG_ENTRIES_POOL_SIZE; ++i) { + std::string tag = (i < tags.size()) ? tags[i]->fullName() : ""; + BookTagEntry *entry = new BookTagEntry(*this, tag, visible); + myTagEntries.push_back(entry); + myTagsTab->addOption(ZLResourceKey("tags"), entry); + } + myTagsDone = true; +} + +void BookInfoDialog::initAuthorEntries() { + bool visible = true; + const AuthorList &authors = myBook->authors(); + myAuthorsDone = false; + myAuthorsTab = &myDialog->createTab(ZLResourceKey("Authors")); + for (std::size_t i = 0; i < AUTHOR_ENTRIES_POOL_SIZE; ++i) { + shared_ptr<Author> author = (i < authors.size()) ? authors[i] : 0; + AuthorDisplayNameEntry *entry = new AuthorDisplayNameEntry(*this, author, visible); + myAuthorEntries.push_back(entry); + myAuthorsTab->addOption(ZLResourceKey("authorDisplayName"), entry); + } + myAuthorsDone = true; +} + |