diff --git a/src/acbf/AcbfBookinfo.cpp b/src/acbf/AcbfBookinfo.cpp index 0bc41f8..632b370 100644 --- a/src/acbf/AcbfBookinfo.cpp +++ b/src/acbf/AcbfBookinfo.cpp @@ -1,692 +1,696 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "AcbfBookinfo.h" #include "AcbfAuthor.h" #include "AcbfContentrating.h" #include "AcbfDatabaseref.h" #include "AcbfLanguage.h" #include "AcbfPage.h" #include "AcbfSequence.h" #include #include #include using namespace AdvancedComicBookFormat; class BookInfo::Private { public: Private() : coverPage(nullptr) {} QList author; QHash title; QHash genre; QList characters; QHash annotation; QHash keywords; Page* coverPage; QList languages; QList sequence; QList databaseRef; QList contentRating; - QString readingDirection; + bool rightToLeft = false; }; BookInfo::BookInfo(Metadata* parent) : QObject(parent) , d(new Private) { qRegisterMetaType("BookInfo*"); d->coverPage = new Page(metadata()->document()); d->coverPage->setIsCoverPage(true); } BookInfo::~BookInfo() = default; Metadata * BookInfo::metadata() { return qobject_cast(parent()); } void BookInfo::toXml(QXmlStreamWriter* writer) { writer->writeStartElement(QStringLiteral("book-info")); Q_FOREACH(Author* author, d->author) { author->toXml(writer); } QHashIterator titles(d->title); while(titles.hasNext()) { titles.next(); writer->writeStartElement(QStringLiteral("book-title")); writer->writeAttribute(QStringLiteral("lang"), titles.key()); writer->writeCharacters(titles.value()); writer->writeEndElement(); } QHashIterator genres(d->genre); while(genres.hasNext()) { genres.next(); writer->writeStartElement(QStringLiteral("genre")); writer->writeAttribute(QStringLiteral("match"), QString::number(genres.value())); writer->writeCharacters(genres.key()); writer->writeEndElement(); } writer->writeStartElement("characters"); writer->writeCharacters(""); Q_FOREACH(const QString& character, d->characters) { writer->writeStartElement("name"); writer->writeCharacters(character); writer->writeEndElement(); } writer->writeEndElement(); QHashIterator annotations(d->annotation); while(annotations.hasNext()) { annotations.next(); writer->writeStartElement(QStringLiteral("annotation")); writer->writeAttribute(QStringLiteral("lang"), annotations.key()); Q_FOREACH(const QString& paragraph, annotations.value()) { writer->writeStartElement(QStringLiteral("p")); writer->writeCharacters(paragraph); writer->writeEndElement(); } writer->writeEndElement(); } QHashIterator keywords(d->keywords); while(keywords.hasNext()) { keywords.next(); writer->writeStartElement(QStringLiteral("keywords")); writer->writeAttribute(QStringLiteral("lang"), keywords.key()); writer->writeCharacters(keywords.value().join(',')); writer->writeEndElement(); } d->coverPage->toXml(writer); writer->writeStartElement(QStringLiteral("languages")); Q_FOREACH(Language* language, d->languages) { language->toXml(writer); } writer->writeEndElement(); Q_FOREACH(Sequence* sequence, d->sequence) { sequence->toXml(writer); } Q_FOREACH(DatabaseRef* ref, d->databaseRef) { ref->toXml(writer); } Q_FOREACH(ContentRating* rating, d->contentRating) { rating->toXml(writer); } //ACBF 1.2 - /* - writer->writeStartElement("characters"); - writer->writeCharacters(d->readingDirection); - writer->writeEndElement(); - */ + // Therefore only write this one when it is useful. + if (d->rightToLeft) { + writer->writeStartElement("reading-direction"); + writer->writeCharacters("RTL"); + writer->writeEndElement(); + } writer->writeEndElement(); } bool BookInfo::fromXml(QXmlStreamReader *xmlReader) { while(xmlReader->readNextStartElement()) { if(xmlReader->name() == QStringLiteral("author")) { Author* newAuthor = new Author(metadata()); if(!newAuthor->fromXml(xmlReader)) { return false; } d->author.append(newAuthor); } else if(xmlReader->name() == QStringLiteral("book-title")) { QString language = xmlReader->attributes().value(QStringLiteral("lang")).toString(); d->title[language] = xmlReader->readElementText(QXmlStreamReader::IncludeChildElements); } else if(xmlReader->name() == QStringLiteral("genre")) { int match = xmlReader->attributes().value(QStringLiteral("match")).toInt(); d->genre[xmlReader->readElementText(QXmlStreamReader::IncludeChildElements)] = match; } else if(xmlReader->name() == QStringLiteral("characters")) { while(xmlReader->readNextStartElement()) { if(xmlReader->name() == QStringLiteral("name")) { d->characters.append(xmlReader->readElementText(QXmlStreamReader::IncludeChildElements)); } else { xmlReader->skipCurrentElement(); } } qDebug() << "Created character entries, we now have" << d->characters.count() << "characters"; } else if(xmlReader->name() == QStringLiteral("annotation")) { QString language = xmlReader->attributes().value(QStringLiteral("lang")).toString(); QStringList paragraphs; while(xmlReader->readNextStartElement()) { if(xmlReader->name() == QStringLiteral("p")) { paragraphs.append(xmlReader->readElementText(QXmlStreamReader::IncludeChildElements)); } else { xmlReader->skipCurrentElement(); } } d->annotation[language] = paragraphs; } else if(xmlReader->name() == QStringLiteral("keywords")) { QString language = xmlReader->attributes().value(QStringLiteral("lang")).toString(); d->keywords[language] = xmlReader->readElementText(QXmlStreamReader::IncludeChildElements).split(','); } else if(xmlReader->name() == QStringLiteral("coverpage")) { if(!d->coverPage->fromXml(xmlReader)) { return false; } } else if(xmlReader->name() == QStringLiteral("languages")) { while(xmlReader->readNextStartElement()) { if(xmlReader->name() == QStringLiteral("text-layer")) { Language* newLanguage = new Language(this); newLanguage->fromXml(xmlReader); d->languages.append(newLanguage); } else { xmlReader->skipCurrentElement(); } } } else if(xmlReader->name() == QStringLiteral("sequence")) { Sequence* newSequence = new Sequence(this); newSequence->fromXml(xmlReader); d->sequence.append(newSequence); } else if(xmlReader->name() == QStringLiteral("databaseref")) { DatabaseRef* newDatabaseRef = new DatabaseRef(this); newDatabaseRef->fromXml(xmlReader); d->databaseRef.append(newDatabaseRef); } else if(xmlReader->name() == QStringLiteral("content-rating")) { ContentRating* newContentRating = new ContentRating(this); newContentRating->fromXml(xmlReader); d->contentRating.append(newContentRating); } else if(xmlReader->name() == QStringLiteral("reading-direction")) { - setReadingDirection(xmlReader->readElementText(QXmlStreamReader::IncludeChildElements).toLower()); + QString direction = xmlReader->readElementText(QXmlStreamReader::IncludeChildElements).toLower(); + if (direction=="rtl") { + setRightToLeft(true); + } else { + setRightToLeft(false); + } } else { qWarning() << Q_FUNC_INFO << "currently unsupported subsection:" << xmlReader->name(); xmlReader->skipCurrentElement(); } } if (xmlReader->hasError()) { qWarning() << Q_FUNC_INFO << "Failed to read ACBF XML document at token" << xmlReader->name() << "(" << xmlReader->lineNumber() << ":" << xmlReader->columnNumber() << ") The reported error was:" << xmlReader->errorString(); } qDebug() << Q_FUNC_INFO << "Created book information for the book with the titles" << d->title.values(); return !xmlReader->hasError(); } QList BookInfo::author() { return d->author; } QStringList BookInfo::authorNames() const { QStringList names; for(Author* author : d->author) { names.append(author->displayName()); } return names; } Author * BookInfo::getAuthor(int index) const { return d->author.at(index); } void BookInfo::addAuthor(QString activity, QString language, QString firstName, QString middleName, QString lastName, QString nickName, QStringList homePages, QStringList emails) { Author* author = new Author(metadata()); author->setActivity(activity); author->setLanguage(language); author->setFirstName(firstName); author->setMiddleName(middleName); author->setLastName(lastName); author->setNickName(nickName); author->setHomePages(homePages); author->setEmails(emails); d->author.append(author); emit authorsChanged(); } void BookInfo::setAuthor(int index, QString activity, QString language, QString firstName, QString middleName, QString lastName, QString nickName, QStringList homePages, QStringList emails) { Author* author = d->author.at(index); author->setActivity(activity); author->setLanguage(language); author->setFirstName(firstName); author->setMiddleName(middleName); author->setLastName(lastName); author->setNickName(nickName); author->setHomePages(homePages); author->setEmails(emails); emit authorsChanged(); } void BookInfo::removeAuthor(int index) { d->author.removeAt(index); emit authorsChanged(); } void BookInfo::addAuthor(Author* author) { d->author.append(author); emit authorsChanged(); } void BookInfo::removeAuthor(Author* author) { d->author.removeAll(author); emit authorsChanged(); } QStringList BookInfo::titleForAllLanguages() { return d->title.values(); } QStringList BookInfo::titleLanguages() { return d->title.keys(); } QString BookInfo::title(QString language) { if (d->title.count()==0) { return ""; } if (!d->title.keys().contains(language)) { language = ""; } if(language.isEmpty() && d->title[language].isEmpty() && d->languages.count()>0) { language = d->languages.at(0)->language(); } QString title = d->title.value(language); if (title.isEmpty()) { title = d->title.values().at(0); } return title; } void BookInfo::setTitle(QString title, QString language) { // Don't allow removal of the default title, just everything else if(title.isEmpty() && !language.isEmpty()) { d->title.remove(language); } else { d->title[language] = title; } emit titleChanged(); } QHash BookInfo::genre() { return d->genre; } QStringList BookInfo::genres() const { return d->genre.keys(); } int BookInfo::genrePercentage(QString genre) const { return d->genre[genre]; } void BookInfo::setGenre(QString genre, int matchPercentage) { bool emitNewGenre = !d->genre.contains(genre); d->genre[genre] = matchPercentage; if(emitNewGenre) { emit genresChanged(); } } void BookInfo::removeGenre(QString genre) { d->genre.remove(genre); emit genresChanged(); } QStringList BookInfo::availableGenres() { return { QStringLiteral("adult"), QStringLiteral("adventure"), QStringLiteral("alternative"), // (abstract, underground ...) QStringLiteral("artbook"), // 1.2 QStringLiteral("biography"), // (biographical comics) QStringLiteral("caricature"), QStringLiteral("children"), QStringLiteral("computer"), // (computers related) QStringLiteral("crime"), QStringLiteral("education"), // (education and science) QStringLiteral("fantasy"), QStringLiteral("history"), // (historical comics) QStringLiteral("horror"), QStringLiteral("humor"), QStringLiteral("manga"), QStringLiteral("military"), // (war ...) QStringLiteral("mystery"), QStringLiteral("non-fiction"), QStringLiteral("politics"), QStringLiteral("real_life"), QStringLiteral("religion"), QStringLiteral("romance"), QStringLiteral("science_fiction"), QStringLiteral("sports"), QStringLiteral("superhero"), // (e.g. Superman, Spiderman … or Super Villains) QStringLiteral("western"), QStringLiteral("other") }; } QStringList BookInfo::characters() { return d->characters; } void BookInfo::addCharacter(QString name) { d->characters.append(name); emit charactersChanged(); } void BookInfo::removeCharacter(QString name) { d->characters.removeAll(name); emit charactersChanged(); } void BookInfo::setCharacters(QStringList characters) { d->characters = characters; emit charactersChanged(); } QList BookInfo::annotationsForAllLanguage() { return d->annotation.values(); } QStringList BookInfo::annotationLanguages() { return d->annotation.keys(); } QStringList BookInfo::annotation(QString language) { if (d->annotation.isEmpty()) { return QStringList(""); } if (!d->annotation.keys().contains(language)) { language = ""; } if(language.isEmpty() && d->annotation.value(language).count()==0) { language = d->languages.at(0)->language(); } QStringList annotation = d->annotation.value(language); if (annotation.count()==0) { annotation = d->annotation.values().at(0); } return annotation; } void BookInfo::setAnnotation(QStringList annotation, QString language) { d->annotation[language] = annotation; } QHash BookInfo::keywordsForAllLanguage() { return d->keywords; } QStringList BookInfo::keywords(QString language) { if (d->keywords.isEmpty()) { return QStringList(""); } if (!d->keywords.keys().contains(language)) { language = ""; } if(language.isEmpty() && d->keywords.value(language).count()==0) { language = d->languages.at(0)->language(); } QStringList keywords = d->keywords.value(language); if (keywords.count()==0) { keywords = d->keywords.values().at(0); } return keywords; } void BookInfo::setKeywords(QStringList keywords, QString language) { d->keywords[language] = keywords; } Page * BookInfo::coverpage() { return d->coverPage; } void BookInfo::setCoverpage(Page* newCover) { d->coverPage = newCover; } QList BookInfo::languages() { return d->languages; } void BookInfo::addLanguage(Language* language) { d->languages.append(language); } void BookInfo::removeLanguage(Language* language) { d->languages.removeAll(language); } QList BookInfo::sequence() { return d->sequence; } void BookInfo::addSequence(Sequence* sequence) { d->sequence.append(sequence); emit sequenceCountChanged(); } void BookInfo::addSequence(int number, QString title, int volume) { Sequence* sequence = new Sequence(this); sequence->setNumber(number); sequence->setTitle(title); sequence->setVolume(volume); addSequence(sequence); } void BookInfo::removeSequence(Sequence* sequence) { d->sequence.removeAll(sequence); emit sequenceCountChanged(); } void BookInfo::removeSequence(int index) { removeSequence(sequence(index)); } Sequence *BookInfo::sequence(int index) const { return d->sequence.at(index); } int BookInfo::sequenceCount() const { return d->sequence.size(); } QList BookInfo::databaseRef() { return d->databaseRef; } void BookInfo::addDatabaseRef(DatabaseRef* databaseRef) { d->databaseRef.append(databaseRef); emit databaseRefCountChanged(); } void BookInfo::addDatabaseRef(QString reference, QString dbname, QString type) { DatabaseRef* dRef = new DatabaseRef(this); dRef->setReference(reference); dRef->setDbname(dbname); dRef->setType(type); addDatabaseRef(dRef); } void BookInfo::removeDatabaseRef(DatabaseRef* databaseRef) { d->databaseRef.removeAll(databaseRef); emit databaseRefCountChanged(); } void BookInfo::removeDatabaseRef(int index) { removeDatabaseRef(databaseRef(index)); } DatabaseRef *BookInfo::databaseRef(int index) { return d->databaseRef.at(index); } int BookInfo::databaseRefCount() { return d->databaseRef.size(); } QList BookInfo::contentRating() { return d->contentRating; } void BookInfo::addContentRating(ContentRating* contentRating) { d->contentRating.append(contentRating); emit contentRatingCountChanged(); } void BookInfo::addContentRating(QString rating, QString type) { ContentRating* CR = new ContentRating(this); CR->setRating(rating); CR->setType(type); addContentRating(CR); } void BookInfo::removeContentRating(ContentRating* contentRating) { d->contentRating.removeAll(contentRating); emit contentRatingCountChanged(); } void BookInfo::removeContentRating(int index) { removeContentRating(contentRating(index)); } ContentRating *BookInfo::contentRating(int index) { return d->contentRating.at(index); } int BookInfo::contentRatingCount() { return d->contentRating.size(); } -QString BookInfo::readingDirection() const +bool BookInfo::rightToLeft() const { - return d->readingDirection; + return d->rightToLeft; } -void BookInfo::setReadingDirection(const QString& readingDirection) { - if (readingDirection == "ltr" || - readingDirection == "rtl") { - d->readingDirection = readingDirection; - } +void BookInfo::setRightToLeft(const bool& rtl) { + d->rightToLeft = rtl; + emit rightToLeftChanged(); } diff --git a/src/acbf/AcbfBookinfo.h b/src/acbf/AcbfBookinfo.h index 4274250..f967f40 100644 --- a/src/acbf/AcbfBookinfo.h +++ b/src/acbf/AcbfBookinfo.h @@ -1,482 +1,487 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #ifndef ACBFBOOKINFO_H #define ACBFBOOKINFO_H #include #include "AcbfMetadata.h" #include /** * \brief Class for handling the book metadata. * * ACBF book-info is all the metadata that relates * to the story inside. * * This class holds all the authors, titles, languages, * summaries, genres, keywords, hashtags and more. * * It also handles adding and removing, as well as storing * and reading it from the xml. * * ACBF can hold multiple authors per book. Authors have their own object. * * ACBF can hold titles, annotations(summaries or descriptions) and * a list of comma seperated keywords in several languages. * * Annotations in particular are a stringlist of paragraphs. * * The library handles retrieving title, keywords and annotation when there is no * language defined as follows: It checks if there is an entry for "", if not, tries * the entry for the first language object, and if that doesn't work, returns the first * value it can find. * * ACBF's language support is further detailed in the Language object. * * ACBF can have multiple genres, but they are limited to a list of keys, given * by availableGenres(). * Genres can also indicate how much they apply on the given story, using * a match percentage. This allows noting that a story is 80% romance, and * 20% western for example. * * ACBF can also hold character names. Character names are a type of tag, and * especially relevant with American style multiverses, but also in Creative * Commons stories because the permissive licenses allow for easier reusage of * existing characters. * * The coverpage is defined in the book-info as a Page object. * * Finally, ACBF can hold metadata about database references, sequences and * content rating. All these too have their own objects. */ namespace AdvancedComicBookFormat { class Author; class Page; class Language; class Sequence; class DatabaseRef; class ContentRating; class ACBF_EXPORT BookInfo : public QObject { Q_OBJECT Q_PROPERTY(QStringList authorNames READ authorNames NOTIFY authorsChanged) Q_PROPERTY(QStringList titleLanguages READ titleLanguages NOTIFY titleChanged) Q_PROPERTY(QStringList genres READ genres NOTIFY genresChanged) Q_PROPERTY(QStringList characters READ characters WRITE setCharacters NOTIFY charactersChanged) Q_PROPERTY(int sequenceCount READ sequenceCount NOTIFY sequenceCountChanged) Q_PROPERTY(int databaseRefCount READ databaseRefCount NOTIFY databaseRefCountChanged) Q_PROPERTY(int contentRatingCount READ contentRatingCount NOTIFY contentRatingCountChanged) + Q_PROPERTY(bool rightToLeft READ rightToLeft WRITE setRightToLeft NOTIFY rightToLeftChanged) public: explicit BookInfo(Metadata* parent = nullptr); ~BookInfo() override; Metadata* metadata(); /** * \brief write the whole book-info section to the XML writer. */ void toXml(QXmlStreamWriter *writer); /** * \brief load the whole book-info section from the xml into this object. * @return True if the xmlReader encountered no errors. */ bool fromXml(QXmlStreamReader *xmlReader); /** * @return The list of authors that worked on this book as author objects. */ QList author(); /** * @return The list of authors that worked on this book as * a stringlist of names. */ QStringList authorNames() const; /** * \brief get an author object by index. * @param index - the index of the author. */ Q_INVOKABLE Author* getAuthor(int index) const; /** * \brief add an author to the list. * @param activity - the role this author played. * @param language - the language of the author in language code, country * code format joined by a dash (not an underscore). * @param firstName - the given name of the author. * @param middleName - the middle name(s) of the author as a string. * @param lastName - the family name of the author. * @param nickName - the nickname of the author. * @param homePages - a homepage url to associate with this author. * @param emails - an email adress to associate with this author. */ Q_INVOKABLE void addAuthor(QString activity, QString language, QString firstName, QString middleName, QString lastName, QString nickName, QStringList homePages, QStringList emails); /** * \brief make changes to an author in the list. * @param index - The index of this author in the author list. * @param activity - the role this author played. * @param language - the language of the author in language code, country * code format joined by a dash (not an underscore). * @param firstName - the given name of the author. * @param middleName - the middle name(s) of the author as a string. * @param lastName - the family name of the author. * @param nickName - the nickname of the author. * @param homePages - a homepage url to associate with this author. * @param emails - an email adress to associate with this author. */ Q_INVOKABLE void setAuthor(int index, QString activity, QString language, QString firstName, QString middleName, QString lastName, QString nickName, QStringList homePages, QStringList emails); /** * \brief remove an author in the list. * @param index - the index of the author to remove. */ Q_INVOKABLE void removeAuthor(int index); /** * \brief add an author to the list. * @param author - the author object to add. */ void addAuthor(Author* author); /** * \brief remove an author to the list. * @param author - the author object to remove. */ void removeAuthor(Author* author); /** * \brief triggers when the authors list changes. */ Q_SIGNAL void authorsChanged(); /** * \brief this holds a list of titles regardless of language. * @return a stringlist with all the titles. */ Q_INVOKABLE QStringList titleForAllLanguages(); /** * @return a list of the languages the titles are in. */ Q_INVOKABLE QStringList titleLanguages(); /** * \brief get the title for the given language. * @param language - the language of which to return the title for. * @return The title for the given language code. * When no language is supplied, returns english title. */ Q_INVOKABLE QString title(QString language = ""); /** * \brief set the title for the given language code. * @param title - the title as a QString * @param language - the language code in language code, country * code format joined by a dash (not an underscore). */ Q_INVOKABLE void setTitle(QString title, QString language = ""); /** * \brief triggers when a title is set for any language. */ Q_SIGNAL void titleChanged(); /** * @return returns a hash of genre keys and their match percentage. */ Q_INVOKABLE QHash genre(); /** * @return a list of strings for the genres. */ Q_INVOKABLE QStringList genres() const; /** * @param genre - the genre for which to return the percentage. * @return an integer between 0 to 100 representing the match * percentage of the given genre. */ Q_INVOKABLE int genrePercentage(QString genre) const; /** * \brief Set a genre and their match percentage. * @param genre - the name of the genre to add. * @param matchPercentage - the percentage of how much this genre matches. */ Q_INVOKABLE void setGenre(QString genre, int matchPercentage = 100); /** * \brief remove the genre from the hashlist. * @param genre - the genre name to remove. */ Q_INVOKABLE void removeGenre(QString genre); /** * \brief triggers when genres are set or removed. */ Q_SIGNAL void genresChanged(); /** * \brief the list of approved genre names. */ Q_INVOKABLE static QStringList availableGenres(); /** * @return character names as a stringlist. */ Q_INVOKABLE QStringList characters(); /** * \brief add a character to the characters list. * @param name - the name of the character to add. */ Q_INVOKABLE void addCharacter(QString name); /** * \brief remove a character from the character list. * @param name - the name of the character to remove. */ Q_INVOKABLE void removeCharacter(QString name); /** * @brief Replace the characters stringlist. * @param characters new string list to use. */ Q_INVOKABLE void setCharacters(QStringList characters); /** * \brief this triggers when the character name list is changed. */ Q_SIGNAL void charactersChanged(); /** * @return a list of annotations, which in turn are stringlists. */ Q_INVOKABLE QList annotationsForAllLanguage(); /** * @return a list of languages the annotation is available in. */ Q_INVOKABLE QStringList annotationLanguages(); /** * @param language - the language for which to return the annotation. * @return the annotation for the given language * as a stringlist of paragraphs */ Q_INVOKABLE QStringList annotation(QString language = ""); // empty string means "default language", as (un)defined by the specification... /** * \brief set an annotation for the given language. * @param annotation - A stringlist of paragraphs which make * up the annotiation. * @param language - The language for which to set the annotation in * language code, country code format joined by a dash (not an underscore). */ Q_INVOKABLE void setAnnotation(QStringList annotation, QString language = ""); /** * @return a hashmap of languages and the keyword stringlists. */ QHash keywordsForAllLanguage(); /** * @param language - the language for which to return the keywords for. * @return a stringlist of keywords in the given language. */ Q_INVOKABLE QStringList keywords(QString language = ""); /** * \brief set the list of keywords for the given language. * @param keywords - A stringlist of keywords * @param language - The language for which to set the annotation in * language code, country code format joined by a dash (not an underscore). */ Q_INVOKABLE void setKeywords(QStringList keywords, QString language = ""); /** * @return the coverpage as a page object. */ Q_INVOKABLE Page* coverpage(); /** * \brief set a cover page. * @param newCover A page object with the new cover. */ void setCoverpage(Page* newCover); /** * @return a list of language objects for determining translations. */ QList languages(); /** * \brief add a language to the list of translations. * @param language - language object to add. */ void addLanguage(Language* language); /** * \brief remove a language from the translations. * @param language - language object to remove. */ void removeLanguage(Language* language); /** * @return a list of sequence objects that describe the series and * collections this book is part of. */ QList sequence(); /** * \brief add a sequence object to indicate this book is part of one. * @param sequence - the sequence object that describes this book's place in * a sequence. */ void addSequence(Sequence* sequence); /** * @brief add a sequence from basic strings. * * @param number - integer representing the number within the sequence. * @param title - the of the sequence, optional. * @param volume - volume of the sequence, optional. */ Q_INVOKABLE void addSequence(int number, QString title = QString(), int volume = 0); /** * \brief remove a sequence object from the list of sequences this book is * part of. * @param sequence - the sequence object that describes this book's place in * a sequence. */ void removeSequence(Sequence* sequence); /** * @brief remove a sequence by index. * @param index - index of sequence to remove. */ Q_INVOKABLE void removeSequence(int index); /** * @brief get a sequence by index. * @param index = index of the sequence to get. */ Q_INVOKABLE Sequence* sequence(int index) const; /** * @brief get total amount of sequences. */ Q_INVOKABLE int sequenceCount() const; /** * @brief fires when the sequence count changes. */ Q_SIGNAL void sequenceCountChanged(); /** * @returns a list of entries that this book has in various databases. */ QList databaseRef(); /** * \brief add a database entry that this book has. * @param databaseRef - a databaseRef object describing this work's place * in a database. */ void addDatabaseRef(DatabaseRef* databaseRef); /** * @brief add a database entry that this book has. * @param reference the entry itself. * @param dbname the name of the database. * @param type the type of entry, optional. */ Q_INVOKABLE void addDatabaseRef(QString reference, QString dbname, QString type=""); /** * \brief remove a database entry that this book has. * @param databaseRef - a databaseRef object describing this work's place * in a database. */ void removeDatabaseRef(DatabaseRef* databaseRef); /** * @brief removeDatabaseRef * @param index of the database reference to remove. */ Q_INVOKABLE void removeDatabaseRef(int index); /** * @brief get databaseRef * @param index - index of the database ref to get. * @return databaseTef at index. */ Q_INVOKABLE DatabaseRef* databaseRef(int index); /** * @brief databaseRefCount * @return amount of database references. */ Q_INVOKABLE int databaseRefCount(); /** * @brief fires when databaseRefCount changes */ Q_SIGNAL void databaseRefCountChanged(); /** * @returns a list of contentRating objects describing the audience for this * book. */ QList contentRating(); /** * \brief add a contentRating object to the contentratings. * @param contentRating - a contentRating object describing the label and * contentrating system. */ void addContentRating(ContentRating* contentRating); /** * @brief add a contentRating object to the contentratings. * @param rating - The label of the rating. * @param type - the system the label belongs to. */ Q_INVOKABLE void addContentRating(QString rating, QString type = QString()); /** * \brief remove a contentRating object from the contentRatings. * @param contentRating - a contentRating object describing the label and * contentrating system. */ void removeContentRating(ContentRating* contentRating); /** * @brief removeContentRating * @param index the entry to remove. */ Q_INVOKABLE void removeContentRating(int index); /** * @brief gets the contentrating by index. * @param index - index of the content rating to get. * @return the content rating for the index. */ Q_INVOKABLE ContentRating* contentRating(int index); /** * @brief contentRatingCount * @return the total amount of content ratings in this book. */ Q_INVOKABLE int contentRatingCount(); /** * @brief fires when contentRatingCount changes. */ Q_SIGNAL void contentRatingCountChanged(); /** * @brief The reading direction for this comic for adjusting the layout. * An ACBF 1.2 feature. - * @return QString with either ltr or rtl. + * @return true when the reading direction is right to left. */ - QString readingDirection() const; + bool rightToLeft() const; /** * @brief set the Reading direction for this comic. This indicates * how the UI will lay out the buttons and controls. * An ACBF 1.2 feature. - * @param readingDirection a QString with either "ltr" or "rtl". + * @param rtl a boolean indicating whether the reading direction is right to left. */ - void setReadingDirection(const QString& readingDirection = "ltr"); + void setRightToLeft(const bool& rtl = false); + /** + * @brief fires when right to left changes. + */ + Q_SIGNAL void rightToLeftChanged(); private: class Private; std::unique_ptr d; }; } #endif//ACBFBOOKINFO_H diff --git a/src/creator/qml/BookMetainfoPage.qml b/src/creator/qml/BookMetainfoPage.qml index 4db0ae1..5386cb4 100644 --- a/src/creator/qml/BookMetainfoPage.qml +++ b/src/creator/qml/BookMetainfoPage.qml @@ -1,989 +1,1001 @@ /* * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ import QtQuick 2.2 import QtQuick.Controls 2.2 as QtControls import org.kde.kirigami 2.1 as Kirigami import "metainfoeditors" /** * @brief Page with form to edit the comic metadata. * * Most metadata entries are quite simple. * * Others, like Author, need a dedicated entry editor (AuthorEntryEditor). */ Kirigami.ScrollablePage { id: root; title: i18nc("title text for the book meta information editor sheet", "Edit Meta Information"); property QtObject model; actions { main: saveAndCloseAction; } Kirigami.Action { id: saveAndCloseAction; text: i18nc("Saves the remaining unsaved edited fields and closes the metainfo editor", "Save and Close Editor"); iconName: "dialog-ok"; shortcut: "Esc"; onTriggered: { // Save the default title/annotation/keywords. root.model.acbfData.metaData.bookInfo.setTitle(defaultTitle.text, ""); root.model.acbfData.metaData.bookInfo.setAnnotation(defaultAnnotation.text.split("\n\n"), ""); var keywords = defaultKeywords.text.split(",") for (var i in keywords) { keywords[i] = keywords[i].trim(); } root.model.acbfData.metaData.bookInfo.setKeywords(keywords, ""); root.model.setDirty(); pageStack.pop(); } } Column { id: contentColumn; width: root.width - (root.leftPadding + root.rightPadding); height: childrenRect.height; spacing: Kirigami.Units.smallSpacing; Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the book title", "Title"); } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { id: defaultTitle; width: parent.width; placeholderText: i18nc("placeholder text for default title text-input", "Write to add default title"); text:root.model.acbfData ? root.model.acbfData.metaData.bookInfo.title("") : ""; } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the default annotation", "Annotation"); } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextArea { id: defaultAnnotation; width: parent.width; placeholderText: i18nc("placeholder text for default annotiation text-area", "Write to add default annotation"); text:root.model.acbfData ? root.model.acbfData.metaData.bookInfo.annotation("").join("\n\n") : ""; } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the keyword list", "Keywords"); } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { id: defaultKeywords; width: parent.width; placeholderText: i18nc("placeholder text for the add new keyword text entry", "Write a comma seperated list of keywords."); text:root.model.acbfData ? root.model.acbfData.metaData.bookInfo.keywords("").join(", ") : ""; } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the author list", "Authors (" + authorRepeater.count + ")"); } Repeater { id: authorRepeater; model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.authorNames : 0; delegate: QtControls.Label { width: parent.width - removeAuthorButton.width - Kirigami.Units.smallSpacing; text: modelData.length > 0 ? modelData : "(unnamed)"; QtControls.Button { id: editAuthorButton; anchors { right: removeAuthorButton.left; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "document-edit"; } height: parent.height; width: height; onClicked: { authorEditor.index = model.index; authorEditor.open(); } } QtControls.Button { id: removeAuthorButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: parent.height; width: height; onClicked: { // When removing, set the model dirty first, and then remove the entry to avoid reference errors. root.model.setDirty(); root.model.acbfData.metaData.bookInfo.removeAuthor(index); } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { width: parent.width - addAuthorButton.width - Kirigami.Units.smallSpacing; placeholderText: i18nc("placeholder text for the add new author text entry", "Write to add new author (nickname)"); Keys.onReturnPressed: addAuthor(); function addAuthor() { if(text !== "") { // Just add an author where only the nickname is defined root.model.acbfData.metaData.bookInfo.addAuthor("", "", "", "", "", text, [""], [""]); root.model.setDirty(); text = ""; } } QtControls.Button { id: addAuthorButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addAuthor(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the genre list", "Genres"); } Repeater { model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.genres : 0; delegate: Item { width: parent.width; height: childrenRect.height; QtControls.Label { id: genreText; width: parent.width - removeGenreButton.width - Kirigami.Units.smallSpacing; text: modelData; QtControls.Button { id: removeGenreButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: parent.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.bookInfo.removeGenre(modelData); } } } QtControls.Slider { anchors { top: genreText.bottom; topMargin: Kirigami.Units.smallSpacing; } from: 0; to: 100; stepSize: 1.0; width: genreText.width; value: root.model.acbfData.metaData.bookInfo.genrePercentage(modelData); onValueChanged: { if(value > 0 && value !== root.model.acbfData.metaData.bookInfo.genrePercentage(modelData)) { root.model.acbfData.metaData.bookInfo.setGenre(modelData, value); root.model.setDirty(); } } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.ComboBox { width: parent.width - addGenreButton.width - Kirigami.Units.smallSpacing; model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.availableGenres().filter(checkGenreInUse) : 0; Keys.onReturnPressed: addGenre(); function addGenre() { root.model.acbfData.metaData.bookInfo.setGenre(currentText); root.model.setDirty(); currentIndex=0; } function checkGenreInUse (genre) { return root.model.acbfData.metaData.bookInfo.genres.indexOf(genre) === -1; } QtControls.Button { id: addGenreButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addGenre(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the character list", "Characters"); } Repeater { model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.characters : 0; delegate: QtControls.TextField { width: parent.width - removeCharacterButton.width - Kirigami.Units.smallSpacing; text: modelData; onEditingFinished: root.model.acbfData.metaData.bookInfo.characters[index] = text; QtControls.Button { id: removeCharacterButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: parent.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.bookInfo.removeCharacter(modelData); } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { width: parent.width - addCharacterButton.width - Kirigami.Units.smallSpacing; placeholderText: i18nc("placeholder text for the add new character text entry", "Write to add new character"); Keys.onReturnPressed: addCharacter(); function addCharacter() { if(text !== "") { root.model.acbfData.metaData.bookInfo.addCharacter(text); root.model.setDirty(); text = ""; } } QtControls.Button { id: addCharacterButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addCharacter(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the sequence list", "Sequence"); } Repeater { id: sequenceListRepeater; model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.sequenceCount : 0; delegate: Item { width: parent.width; height: childrenRect.height; function updateSeries() { root.model.acbfData.metaData.bookInfo.sequence(modelData).title = seriesTextField.text; if (numberField.value !== root.model.acbfData.metaData.bookInfo.sequence(modelData).number) { root.model.acbfData.metaData.bookInfo.sequence(modelData).number = numberField.value; } if (volumeField.value !== root.model.acbfData.metaData.bookInfo.sequence(modelData).volume) { root.model.acbfData.metaData.bookInfo.sequence(modelData).volume = volumeField.value; } root.model.setDirty(); } QtControls.TextField { id: seriesTextField; width: parent.width - removeSequenceButton.width - Kirigami.Units.smallSpacing; text: root.model.acbfData.metaData.bookInfo.sequence(modelData).title; onEditingFinished: parent.updateSeries(); } QtControls.SpinBox { anchors { top: seriesTextField.bottom; topMargin: Kirigami.Units.smallSpacing; } value : root.model.acbfData.metaData.bookInfo.sequence(modelData).number; width : (seriesTextField.width+Kirigami.Units.smallSpacing)/2; id: numberField; onValueChanged: parent.updateSeries(); } QtControls.SpinBox { anchors { left: numberField.right; leftMargin: Kirigami.Units.smallSpacing; top: seriesTextField.bottom; topMargin: Kirigami.Units.smallSpacing; } value : root.model.acbfData.metaData.bookInfo.sequence(modelData).volume; width : (seriesTextField.width/2)-(Kirigami.Units.smallSpacing*1.5); id: volumeField; onValueChanged: parent.updateSeries(); } QtControls.Button { id: removeSequenceButton; anchors { left: seriesTextField.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: seriesTextField.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.bookInfo.removeSequence(index); } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { width: parent.width - addSequenceButton.width - Kirigami.Units.smallSpacing; placeholderText: i18nc("placeholder text for the add new series text entry", "Write to add new series"); Keys.onReturnPressed:addSequence(); function addSequence() { if(text !== "") { root.model.acbfData.metaData.bookInfo.addSequence(0, text); root.model.setDirty(); text = ""; } } QtControls.Button { id: addSequenceButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addSequence(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the database reference list", "Database References"); } Repeater { model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.databaseRefCount : 0; delegate: Item { width: parent.width; height: childrenRect.height; function updateDatabaseRef() { root.model.acbfData.metaData.bookInfo.databaseRef(modelData).reference = referenceTextField.text root.model.acbfData.metaData.bookInfo.databaseRef(modelData).dbname = databaseNameField.text root.model.acbfData.metaData.bookInfo.databaseRef(modelData).type = referenceTypeField.text root.model.setDirty(); } QtControls.TextField { id: referenceTextField; width: parent.width - removeReferenceButton.width - Kirigami.Units.smallSpacing; text: root.model.acbfData.metaData.bookInfo.databaseRef(modelData).reference; onEditingFinished: parent.updateDatabaseRef(); } QtControls.TextField { anchors { top: referenceTextField.bottom; topMargin: Kirigami.Units.smallSpacing; } width : (referenceTextField.width+Kirigami.Units.smallSpacing)/2; id: databaseNameField; text: root.model.acbfData.metaData.bookInfo.databaseRef(modelData).dbname; onEditingFinished: parent.updateDatabaseRef(); } QtControls.TextField { anchors { left: databaseNameField.right; leftMargin: Kirigami.Units.smallSpacing; top: referenceTextField.bottom; topMargin: Kirigami.Units.smallSpacing; } width : (referenceTextField.width/2)-(Kirigami.Units.smallSpacing*1.5); id: referenceTypeField; text: root.model.acbfData.metaData.bookInfo.databaseRef(modelData).type; placeholderText: i18nc("placeholder text for the add reference type text entry", "Write to add reference type"); onEditingFinished: parent.updateDatabaseRef(); } QtControls.Button { id: removeReferenceButton; anchors { left: referenceTextField.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: referenceTextField.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.bookInfo.removeDatabaseRef(index); } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } Item { width: parent.width; height: childrenRect.height; function addReference() { if(addReferenceField.text !== "" && addDatabaseNameField.text !== "") { root.model.acbfData.metaData.bookInfo.addDatabaseRef(addReferenceField.text, addDatabaseNameField.text); root.model.setDirty(); addReferenceField.text = ""; addDatabaseNameField.text = ""; } } QtControls.TextField { id: addReferenceField width: parent.width - addReferenceButton.width - Kirigami.Units.smallSpacing; placeholderText: i18nc("placeholder text for the add new reference text entry", "Write to add new reference"); Keys.onReturnPressed: parent.addReference(); } QtControls.TextField { id: addDatabaseNameField anchors { top: addReferenceField.bottom; topMargin: Kirigami.Units.smallSpacing; } width: parent.width - addReferenceButton.width - Kirigami.Units.smallSpacing; placeholderText: i18nc("placeholder text for the add databasename text entry", "Write to add database name for new reference."); Keys.onReturnPressed: parent.addReference(); } QtControls.Button { id: addReferenceButton; anchors { left: addReferenceField.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: addReferenceField.height; width: height; onClicked: parent.addReference(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the edit field for the content rating list", "Content Ratings"); } Repeater { model: root.model.acbfData ? root.model.acbfData.metaData.bookInfo.contentRatingCount : 0; delegate: Item { width: parent.width; height: childrenRect.height; function updateRating() { root.model.acbfData.metaData.bookInfo.contentRating(modelData).rating = ratingNameField.text root.model.acbfData.metaData.bookInfo.contentRating(modelData).type = systemNameField.text root.model.setDirty(); } QtControls.TextField { width : (parent.width-removeRatingButton.width+Kirigami.Units.smallSpacing)/2; id: ratingNameField; text: root.model.acbfData.metaData.bookInfo.contentRating(modelData).rating; onEditingFinished: parent.updateRating(); } QtControls.TextField { anchors { left: ratingNameField.right; leftMargin: Kirigami.Units.smallSpacing; } width : ((parent.width-removeRatingButton.width)/2)-(Kirigami.Units.smallSpacing*1.5); id: systemNameField; text: root.model.acbfData.metaData.bookInfo.contentRating(modelData).type; placeholderText: i18nc("placeholder text for the add reference type text entry", "Write to add reference type"); onEditingFinished: parent.updateRating(); } QtControls.Button { id: removeRatingButton; anchors { left: systemNameField.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: systemNameField.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.bookInfo.removeContentRating(index); } } } } Item { width: parent.width; height: childrenRect.height; function addRating() { if(addRatingField.text !== "" && addSystemField.text !== "") { root.model.acbfData.metaData.bookInfo.addContentRating(addRatingField.text, addSystemField.text); root.model.setDirty(); addRatingField.text = ""; addSystemField.text = ""; } } - QtControls.TextField { - width : (parent.width-addRatingButton.width+Kirigami.Units.smallSpacing)/2; - id: addRatingField; - placeholderText: i18nc("placeholder text for the add content rating text entry", "Write to add rating label."); - onEditingFinished: parent.addRating(); + QtControls.TextField { + width : (parent.width-addRatingButton.width+Kirigami.Units.smallSpacing)/2; + id: addRatingField; + placeholderText: i18nc("placeholder text for the add content rating text entry", "Write to add rating label."); + onEditingFinished: parent.addRating(); + } + QtControls.TextField { + anchors { + left: addRatingField.right; + leftMargin: Kirigami.Units.smallSpacing; } - QtControls.TextField { - anchors { - left: addRatingField.right; - leftMargin: Kirigami.Units.smallSpacing; - } - width : ((parent.width-addRatingButton.width)/2)-(Kirigami.Units.smallSpacing*1.5); - id: addSystemField; - placeholderText: i18nc("placeholder text for the add content rating system text entry", "Write to add rating system."); - onEditingFinished: parent.addRating(); + width : ((parent.width-addRatingButton.width)/2)-(Kirigami.Units.smallSpacing*1.5); + id: addSystemField; + placeholderText: i18nc("placeholder text for the add content rating system text entry", "Write to add rating system."); + onEditingFinished: parent.addRating(); + } + QtControls.Button { + id: addRatingButton; + anchors { + left: addSystemField.right; + leftMargin: Kirigami.Units.smallSpacing; } - QtControls.Button { - id: addRatingButton; - anchors { - left: addSystemField.right; - leftMargin: Kirigami.Units.smallSpacing; - } - contentItem: Kirigami.Icon { - source: "list-add"; - } - height: addSystemField.height; - width: height; - onClicked: parent.addRating(); + contentItem: Kirigami.Icon { + source: "list-add"; } + height: addSystemField.height; + width: height; + onClicked: parent.addRating(); } + } + Kirigami.Heading { + width: parent.width; + height: paintedHeight + Kirigami.Units.smallSpacing * 2; + text: i18nc("label text for the form for reading direction.", "Reading Direction"); + } + QtControls.CheckBox { + width: parent.width; + text: i18nc("label text for right to left checkbox.", "Right to left."); + checked: root.model.acbfData.metaData.bookInfo.rightToLeft; + onCheckStateChanged: root.model.acbfData.metaData.bookInfo.rightToLeft = checked; + } + Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the form for the publishing info list", "Publisher Info"); } QtControls.Label { text: i18nc("Label for publisher", "Publisher:"); } QtControls.TextField { width : parent.width; id: publisher; placeholderText: i18nc("placeholder text for the publisher entry", "Write to add publisher"); text: root.model.acbfData? root.model.acbfData.metaData.publishInfo.publisher: ""; onEditingFinished: { if (root.model.acbfData && text !=="") { root.model.acbfData.metaData.publishInfo.publisher = text root.model.setDirty(); } } } QtControls.Label { text: i18nc("Label for publishing date", "Publishing Date:"); } Item { width : parent.width; id: publishingDate; height: childrenRect.height; property date publishingDate: root.model.acbfData.metaData.publishInfo.publishDate; function changePublishDate() { root.model.acbfData.metaData.publishInfo.setPublishDateFromInts(pdYear.text, (pdMonth.currentIndex+1), pdDate.value); root.model.setDirty(); } QtControls.TextField { id: pdYear width: (parent.width-(Kirigami.Units.smallSpacing*2))/3; text: parent.publishingDate.getFullYear(); onEditingFinished: parent.changePublishDate(); inputMask: "9999" inputMethodHints: Qt.ImhFormattedNumbersOnly; } QtControls.ComboBox { id: pdMonth anchors { left: pdYear.right; margins: Kirigami.Units.smallSpacing; } model: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] width: (parent.width-(Kirigami.Units.smallSpacing*2))/3; currentIndex: parent.publishingDate.getMonth(); displayText: Qt.locale().monthName(currentText, Locale.LongFormat); onActivated: parent.changePublishDate(); delegate: QtControls.ItemDelegate { text:Qt.locale().monthName(modelData, Locale.LongFormat); } } QtControls.SpinBox { id: pdDate anchors { left: pdMonth.right; margins: Kirigami.Units.smallSpacing; } width: (parent.width-(Kirigami.Units.smallSpacing*2))/3; height: pdMonth.height; from: 1; to: 31; editable: true; value: parent.publishingDate.getDate(); onValueChanged: parent.changePublishDate(); } } QtControls.Label { text: i18nc("Label for city", "City:"); } QtControls.TextField { width : parent.width; id: city; placeholderText: i18nc("placeholder text for the publishing city entry", "Write to add city"); text: root.model.acbfData? root.model.acbfData.metaData.publishInfo.city: ""; onEditingFinished: { if (root.model.acbfData && text !=="") { root.model.acbfData.metaData.publishInfo.city = text ; root.model.setDirty(); } } } QtControls.Label { text: i18nc("Label for isbn", "ISBN:"); } QtControls.TextField { width : parent.width; id: isbn; placeholderText: i18nc("placeholder text for the publishing isbn entry", "Write to add isbn"); text: root.model.acbfData? root.model.acbfData.metaData.publishInfo.isbn: ""; onEditingFinished: { if (root.model.acbfData && text !=="") { root.model.acbfData.metaData.publishInfo.isbn = text root.model.setDirty(); } } } QtControls.Label { text: i18nc("Label for license", "License:"); } QtControls.TextField { width : parent.width; id: license; placeholderText: i18nc("placeholder text for the publishing license entry", "Write to add license"); text: root.model.acbfData? root.model.acbfData.metaData.publishInfo.license: ""; onEditingFinished: { if (root.model.acbfData && text !=="") { root.model.acbfData.metaData.publishInfo.license = text root.model.setDirty(); } } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the form for the document info list", "Document Authors"); } Repeater { id: docAuthorRepeater; model: root.model.acbfData ? root.model.acbfData.metaData.documentInfo.authorNames : 0; delegate: QtControls.Label { width: parent.width - removeDocAuthorButton.width - Kirigami.Units.smallSpacing; text: modelData.length > 0 ? modelData : "(unnamed)"; QtControls.Button { id: editDocAuthorButton; anchors { right: removeDocAuthorButton.left; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "document-edit"; } height: parent.height; width: height; onClicked: { docAuthorEditor.index = model.index; docAuthorEditor.open(); } } QtControls.Button { id: removeDocAuthorButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: parent.height; width: height; onClicked: { // When removing, set the model dirty first, and then remove the entry to avoid reference errors. root.model.setDirty(); root.model.acbfData.metaData.documentInfo.removeAuthor(index); } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { width: parent.width - addDocAuthorButton.width - Kirigami.Units.smallSpacing; placeholderText: i18nc("placeholder text for the add new author text entry", "Write to add new author (nickname)"); Keys.onReturnPressed: addAuthor(); function addAuthor() { if(text !== "") { // Just add an author where only the nickname is defined root.model.acbfData.metaData.documentInfo.addAuthor("", "", "", "", "", text, [""], [""]); root.model.setDirty(); text = ""; } } QtControls.Button { id: addDocAuthorButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addAuthor(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the form for the sources list", "Document Sources"); } Repeater { model: root.model.acbfData ? root.model.acbfData.metaData.documentInfo.source : 0; delegate: Item { width: parent.width; height: childrenRect.height; QtControls.TextField { id: sourceText; width: parent.width - removeSourceButton.width - Kirigami.Units.smallSpacing; text: modelData; onEditingFinished: root.model.acbfData.metaData.documentInfo.sources[index] = text; QtControls.Button { id: removeSourceButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: parent.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.documentInfo.removeSource(index); } } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { width: parent.width - addSourceButton.width - Kirigami.Units.smallSpacing; Keys.onReturnPressed: addEntry(); function addEntry() { if (text !== "") { root.model.acbfData.metaData.documentInfo.source.push(text); root.model.setDirty(); text = ""; } } QtControls.Button { id: addSourceButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addEntry(); } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the form for the history list", "Document History"); } Repeater { model: root.model.acbfData ? root.model.acbfData.metaData.documentInfo.history : 0; delegate: Item { width: parent.width; height: childrenRect.height; QtControls.TextField { id: historyText; width: parent.width - removeHistoryButton.width - Kirigami.Units.smallSpacing; text: modelData; onEditingFinished: root.model.acbfData.metaData.documentInfo.history[index] = text; QtControls.Button { id: removeHistoryButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-remove"; } height: parent.height; width: height; onClicked: { root.model.setDirty(); root.model.acbfData.metaData.documentInfo.removeHistoryLine(index); } } } } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } QtControls.TextField { width: parent.width - addHistoryButton.width - Kirigami.Units.smallSpacing; Keys.onReturnPressed: addEntry(); function addEntry() { if (text !== "") { root.model.acbfData.metaData.documentInfo.history.push(text); root.model.setDirty(); text = ""; } } QtControls.Button { id: addHistoryButton; anchors { left: parent.right; leftMargin: Kirigami.Units.smallSpacing; } contentItem: Kirigami.Icon { source: "list-add"; } height: parent.height; width: height; onClicked: parent.addEntry(); } } Item { width: parent.width; height: Kirigami.Units.smallSpacing; } Item { width: parent.width; height: childrenRect.height; QtControls.Label { id: versionLabel; height: versionSpinBox.height; text: i18nc("Label for the document version spinbox","Document Version:"); } QtControls.SpinBox { id: versionSpinBox; anchors { top: versionLabel.top; left: versionLabel.right; leftMargin: Kirigami.Units.smallSpacing; } width: parent.width - (Kirigami.Units.smallSpacing*2) - versionLabel.width - addHistoryButton.width; value: root.model.acbfData.metaData.documentInfo.version; onValueChanged: { if (root.model.acbfData.metaData.documentInfo.version!==value) { root.model.acbfData.metaData.documentInfo.version = value; } } } } Kirigami.Heading { width: parent.width; height: paintedHeight + Kirigami.Units.smallSpacing * 2; text: i18nc("label text for the form for the body background color.", "General Page Background Color"); } QtControls.TextField { text: root.model.acbfData.body.bgcolor; placeholderText: "#ffffff"; onEditingFinished: root.model.acbfData.body.bgcolor = text; } AuthorEntryEditor { id: authorEditor; bookinfo: root.model.acbfData.metaData.bookInfo; onSave: { root.model.acbfData.metaData.bookInfo.setAuthor(index, activity, language, firstName, middleName, lastName, nickName, homePage, email); root.model.setDirty(); } } AuthorEntryEditor { id: docAuthorEditor; bookinfo: root.model.acbfData.metaData.documentInfo; onSave: { root.model.acbfData.metaData.documentInfo.setAuthor(index, activity, language, firstName, middleName, lastName, nickName, homePage, email); root.model.setDirty(); } } } }