diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .kdev4 src.kdev4 .directory +CMakeLists.txt.user diff --git a/src/acbf/AcbfAuthor.h b/src/acbf/AcbfAuthor.h --- a/src/acbf/AcbfAuthor.h +++ b/src/acbf/AcbfAuthor.h @@ -61,6 +61,8 @@ class ACBF_EXPORT Author : public QObject { Q_OBJECT + Q_PROPERTY(QStringList homePages READ homePages WRITE setHomePages NOTIFY homePagesChanged) + Q_PROPERTY(QStringList emails READ emails WRITE setEmails NOTIFY emailsChanged) public: // Author is used in both Bookinfo and Documentinfo, and as such it is parented to Metadata explicit Author(Metadata* parent = nullptr); @@ -168,12 +170,20 @@ * @param homepage - the url of the homepage as a string. */ Q_INVOKABLE void addHomePage(const QString& homepage); - + /** + * @brief remove homepage by index. + * @param index - index of the homepage to remove. + */ + Q_INVOKABLE void removeHomePage(const int& index); /** * \brief Set the homepages associated with this author. * @param homepages - homepages as a string. */ Q_INVOKABLE void setHomePages(const QStringList& homepages); + /** + * @brief fires when the homepage list changes. + */ + Q_SIGNAL void homePagesChanged(); /** * @return The email adresses associated with this author as a QStringList. @@ -185,11 +195,20 @@ * @param email - email as a string. */ Q_INVOKABLE void addEmail(const QString& email); + /** + * @brief remove email by index. + * @param index - index of the email to remove. + */ + Q_INVOKABLE void removeEmail(const int& index); /** * \brief Add an email adresses associated with this author. * @param emails - email dresses as a stringlist. */ Q_INVOKABLE void setEmails(const QStringList& emails); + /** + * @brief fires when the email list changes. + */ + Q_SIGNAL void emailsChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfAuthor.cpp b/src/acbf/AcbfAuthor.cpp --- a/src/acbf/AcbfAuthor.cpp +++ b/src/acbf/AcbfAuthor.cpp @@ -221,11 +221,19 @@ void Author::addHomePage(const QString& homepage) { d->homePage.append(homepage); + emit homePagesChanged(); +} + +void Author::removeHomePage(const int &index) +{ + d->homePage.removeAt(index); + emit homePagesChanged(); } void Author::setHomePages(const QStringList& homepages) { d->homePage = homepages; + emit homePagesChanged(); } QStringList Author::emails() const @@ -236,9 +244,17 @@ void Author::addEmail(const QString& email) { d->email.append(email); + emit emailsChanged(); +} + +void Author::removeEmail(const int &index) +{ + d->email.removeAt(index); + emit emailsChanged(); } void Author::setEmails(const QStringList& emails) { d->email = emails; + emit emailsChanged(); } diff --git a/src/acbf/AcbfBody.h b/src/acbf/AcbfBody.h --- a/src/acbf/AcbfBody.h +++ b/src/acbf/AcbfBody.h @@ -46,6 +46,8 @@ class ACBF_EXPORT Body : public QObject { Q_OBJECT + Q_PROPERTY(QString bgcolor READ bgcolor WRITE setBgcolor NOTIFY bgcolorChanged) + Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged) public: explicit Body(Document* parent = nullptr); ~Body(); @@ -76,6 +78,10 @@ * @param newColor - a String with an 8bit per channel rgb hexcode (#ff00ff, or the like) */ void setBgcolor(const QString& newColor); + /** + * @brief fires when the background color changes. + */ + Q_SIGNAL void bgcolorChanged(); /** * @return a QList of all the pages stored currently. @@ -86,7 +92,7 @@ * @param index - the index of the page. * @return the page object at the given index. */ - Page* page(int index) const; + Q_INVOKABLE Page* page(int index) const; /** * @param page - The page for which to return the index. @@ -101,14 +107,22 @@ * \brief remove the given page object from this body. * @param page - the page to remove. */ - void removePage(Page* page); - + void removePage(Page* page); /** * \brief Swap two pages in the list. * @param swapThis - the first page to swap. * @param withThis - the second page to swap. */ bool swapPages(Page* swapThis, Page* withThis); + /** + * @brief pageCount + * @return + */ + int pageCount(); + /** + * @brief pageCountChanged + */ + Q_SIGNAL void pageCountChanged(); private: class Private; diff --git a/src/acbf/AcbfBody.cpp b/src/acbf/AcbfBody.cpp --- a/src/acbf/AcbfBody.cpp +++ b/src/acbf/AcbfBody.cpp @@ -94,6 +94,7 @@ void Body::setBgcolor(const QString& newColor) { d->bgcolor = newColor; + emit bgcolorChanged(); } QList Body::pages() const @@ -119,11 +120,13 @@ else { d->pages.append(page); } + emit pageCountChanged(); } void Body::removePage(Page* page) { d->pages.removeAll(page); + emit pageCountChanged(); } bool Body::swapPages(Page* swapThis, Page* withThis) @@ -132,7 +135,13 @@ int index2 = d->pages.indexOf(withThis); if(index1 > -1 && index2 > -1) { d->pages.swap(index1, index2); + emit pageCountChanged(); return true; } return false; } + +int Body::pageCount() +{ + return d->pages.size(); +} diff --git a/src/acbf/AcbfBookinfo.h b/src/acbf/AcbfBookinfo.h --- a/src/acbf/AcbfBookinfo.h +++ b/src/acbf/AcbfBookinfo.h @@ -85,7 +85,12 @@ 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 NOTIFY charactersChanged) + Q_PROPERTY(QStringList characters READ characters WRITE setCharacters NOTIFY charactersChanged) + Q_PROPERTY(QStringList languageEntryList READ languageEntryList NOTIFY languageEntryListChanged) + 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; @@ -244,6 +249,12 @@ * @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. */ @@ -280,19 +291,19 @@ * @param language - the language for which to return the keywords for. * @return a stringlist of keywords in the given language. */ - QStringList keywords(QString 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). */ - void setKeywords(QStringList keywords, QString language = ""); + Q_INVOKABLE void setKeywords(QStringList keywords, QString language = ""); /** * @return the coverpage as a page object. */ - Page* coverpage(); + Q_INVOKABLE Page* coverpage(); /** * \brief set a cover page. * @param newCover A page object with the new cover. @@ -308,11 +319,33 @@ * @param language - language object to add. */ void addLanguage(Language* language); + + /** + * @brief languageEntryList + * @return a list of languages for the language text layers. + */ + QStringList languageEntryList(); + /** + * @brief fires when the language entry list changes. + */ + Q_SIGNAL void languageEntryListChanged(); + + /** + * \brief add a language to the list of translations. + * @param language - language for which to add a language object. + * @param show - whether to set the language object to 'show'. + */ + Q_INVOKABLE void addLanguage(QString language="", bool show=false); /** * \brief remove a language from the translations. * @param language - language object to remove. */ void removeLanguage(Language* language); + /** + * @brief removeLanguage + * @param index + */ + Q_INVOKABLE void removeLanguage(int index); /** * @return a list of sequence objects that describe the series and @@ -325,6 +358,15 @@ * 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. @@ -333,6 +375,26 @@ */ 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. */ @@ -343,12 +405,40 @@ * 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 @@ -361,27 +451,56 @@ * 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 setRightToLeft(const bool& rtl = false); + /** + * @brief fires when right to left changes. */ - void setReadingDirection(const QString& readingDirection = "ltr"); + Q_SIGNAL void rightToLeftChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfBookinfo.cpp b/src/acbf/AcbfBookinfo.cpp --- a/src/acbf/AcbfBookinfo.cpp +++ b/src/acbf/AcbfBookinfo.cpp @@ -50,7 +50,7 @@ QList sequence; QList databaseRef; QList contentRating; - QString readingDirection; + bool rightToLeft = false; }; BookInfo::BookInfo(Metadata* parent) @@ -145,11 +145,12 @@ } //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(); } @@ -246,7 +247,12 @@ } 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 { @@ -455,6 +461,12 @@ emit charactersChanged(); } +void BookInfo::setCharacters(QStringList characters) +{ + d->characters = characters; + emit charactersChanged(); +} + QList BookInfo::annotationsForAllLanguage() { return d->annotation.values(); @@ -467,6 +479,9 @@ QStringList BookInfo::annotation(QString language) { + if (d->annotation.isEmpty()) { + return QStringList(""); + } if (!d->annotation.keys().contains(language)) { language = ""; } @@ -496,6 +511,10 @@ QStringList BookInfo::keywords(QString language) { + if (d->keywords.isEmpty()) { + return QStringList(""); + } + if (!d->keywords.keys().contains(language)) { language = ""; } @@ -536,11 +555,35 @@ void BookInfo::addLanguage(Language* language) { d->languages.append(language); + emit languageEntryListChanged(); +} + +QStringList BookInfo::languageEntryList() +{ + QStringList lang; + for (int i=0; ilanguages.size(); i++) { + lang.append(d->languages.at(i)->language()); + } + return lang; +} + +void BookInfo::addLanguage(QString language, bool show) +{ + Language* lang = new Language(this); + lang->setLanguage(language); + lang->setShow(show); + addLanguage(lang); } void BookInfo::removeLanguage(Language* language) { d->languages.removeAll(language); + emit languageEntryListChanged(); +} + +void BookInfo::removeLanguage(int index) +{ + removeLanguage(d->languages.at(index)); } QList BookInfo::sequence() @@ -551,11 +594,38 @@ 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() @@ -567,11 +637,37 @@ 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() @@ -582,20 +678,43 @@ 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(); } -QString BookInfo::readingDirection() const + +void BookInfo::removeContentRating(int index) { - return d->readingDirection; + removeContentRating(contentRating(index)); } -void BookInfo::setReadingDirection(const QString& readingDirection) { - if (readingDirection == "ltr" || - readingDirection == "rtl") { - d->readingDirection = readingDirection; - } +ContentRating *BookInfo::contentRating(int index) +{ + return d->contentRating.at(index); +} + +int BookInfo::contentRatingCount() +{ + return d->contentRating.size(); +} +bool BookInfo::rightToLeft() const +{ + return d->rightToLeft; +} + +void BookInfo::setRightToLeft(const bool& rtl) { + d->rightToLeft = rtl; + emit rightToLeftChanged(); } diff --git a/src/acbf/AcbfContentrating.h b/src/acbf/AcbfContentrating.h --- a/src/acbf/AcbfContentrating.h +++ b/src/acbf/AcbfContentrating.h @@ -39,6 +39,8 @@ class ACBF_EXPORT ContentRating : public QObject { Q_OBJECT + Q_PROPERTY(QString rating READ rating WRITE setRating NOTIFY ratingChanged) + Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged) public: explicit ContentRating(BookInfo* parent = nullptr); ~ContentRating() override; @@ -56,22 +58,30 @@ /** * @return the system that the content rating belongs to. */ - QString type() const; + Q_INVOKABLE QString type() const; /** * \brief set the system that defines this rating. * @param type - the name of the system. */ - void setType(const QString& type); + Q_INVOKABLE void setType(const QString& type); + /** + * @brief fires when the type changes. + */ + Q_SIGNAL void typeChanged(); /** * @return the rating label as a string. */ - QString rating() const; + Q_INVOKABLE QString rating() const; /** * \brief set the rating. * @param rating - the name of the rating label as a QString. */ - void setRating(const QString& rating); + Q_INVOKABLE void setRating(const QString& rating); + /** + * @brief fires when the rating changes. + */ + Q_SIGNAL void ratingChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfContentrating.cpp b/src/acbf/AcbfContentrating.cpp --- a/src/acbf/AcbfContentrating.cpp +++ b/src/acbf/AcbfContentrating.cpp @@ -38,6 +38,7 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("ContentRating*"); } ContentRating::~ContentRating() = default; @@ -66,6 +67,7 @@ void ContentRating::setType(const QString& type) { d->type = type; + emit typeChanged(); } QString ContentRating::rating() const @@ -76,4 +78,5 @@ void ContentRating::setRating(const QString& rating) { d->rating = rating; + emit ratingChanged(); } diff --git a/src/acbf/AcbfDatabaseref.h b/src/acbf/AcbfDatabaseref.h --- a/src/acbf/AcbfDatabaseref.h +++ b/src/acbf/AcbfDatabaseref.h @@ -41,6 +41,9 @@ class ACBF_EXPORT DatabaseRef : public QObject { Q_OBJECT + Q_PROPERTY(QString dbname READ dbname WRITE setDbname NOTIFY dbnameChanged) + Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged) + Q_PROPERTY(QString reference READ reference WRITE setReference NOTIFY referenceChanged) public: explicit DatabaseRef(BookInfo* parent = nullptr); ~DatabaseRef() override; @@ -58,32 +61,43 @@ /** * @return the name of the database. */ - QString dbname() const; + Q_INVOKABLE QString dbname() const; /** * \brief set the name of the database for this reference. * @param dbname - the name of the database. */ - void setDbname(const QString& dbname); - + Q_INVOKABLE void setDbname(const QString& dbname); + /** + * @brief fires when the dbname changes; + */ + Q_SIGNAL void dbnameChanged(); /** * @returns the type of reference the reference is. */ - QString type() const; + Q_INVOKABLE QString type() const; /** * \brief set which type of reference the reference is. * @param type - the type of reference. */ - void setType(const QString& type); - + Q_INVOKABLE void setType(const QString& type); + /** + * @brief fires when the type of the reference changes. + */ + Q_SIGNAL void typeChanged(); /** * @returns the reference. */ - QString reference() const; + Q_INVOKABLE QString reference() const; /** * \brief set the reference as a string. * @param reference - the reference a QString. */ - void setReference(const QString& reference); + Q_INVOKABLE void setReference(const QString& reference); + /** + * @brief fires when the reference that this object has of the book + * is changed. + */ + Q_SIGNAL void referenceChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfDatabaseref.cpp b/src/acbf/AcbfDatabaseref.cpp --- a/src/acbf/AcbfDatabaseref.cpp +++ b/src/acbf/AcbfDatabaseref.cpp @@ -39,6 +39,7 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("DatabaseRef*"); } DatabaseRef::~DatabaseRef() = default; @@ -56,7 +57,7 @@ bool DatabaseRef::fromXml(QXmlStreamReader *xmlReader) { - setDbname(xmlReader->attributes().value(QStringLiteral("volume")).toString()); + setDbname(xmlReader->attributes().value(QStringLiteral("dbname")).toString()); setType(xmlReader->attributes().value(QStringLiteral("type")).toString()); setReference(xmlReader->readElementText(QXmlStreamReader::IncludeChildElements)); qDebug() << Q_FUNC_INFO << "Created a database reference for the database" << dbname() << "with reference" << reference(); @@ -71,6 +72,7 @@ void DatabaseRef::setDbname(const QString& dbname) { d->dbname = dbname; + emit dbnameChanged(); } QString DatabaseRef::type() const @@ -81,6 +83,7 @@ void DatabaseRef::setType(const QString& type) { d->type = type; + emit typeChanged(); } QString DatabaseRef::reference() const @@ -91,4 +94,5 @@ void DatabaseRef::setReference(const QString& reference) { d->reference = reference; + emit referenceChanged(); } diff --git a/src/acbf/AcbfDocument.h b/src/acbf/AcbfDocument.h --- a/src/acbf/AcbfDocument.h +++ b/src/acbf/AcbfDocument.h @@ -53,6 +53,7 @@ { Q_OBJECT Q_PROPERTY(Metadata* metaData READ metaData NOTIFY metaDataChanged) + Q_PROPERTY(Body* body READ body NOTIFY bodyChanged) public: explicit Document(QObject* parent = nullptr); ~Document() override; @@ -72,7 +73,7 @@ */ Metadata* metaData() const; /** - * \brief triggers when the metadata is changed. + * @brief fires when the metadata is changed. */ Q_SIGNAL void metaDataChanged(); @@ -80,6 +81,10 @@ * @returns the Body object. */ Body* body() const; + /** + * @return fires when the body changes. Not used. + */ + Q_SIGNAL void bodyChanged(); /** * @brief The reference section. diff --git a/src/acbf/AcbfDocument.cpp b/src/acbf/AcbfDocument.cpp --- a/src/acbf/AcbfDocument.cpp +++ b/src/acbf/AcbfDocument.cpp @@ -67,7 +67,7 @@ writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement(QStringLiteral("ACBF")); - writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://www.fictionbook-lib.org/xml/acbf/1.0")); + writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://www.acbf.info/xml/acbf/1.1")); d->metaData->toXml(&writer); d->body->toXml(&writer); writer.writeEndElement(); diff --git a/src/acbf/AcbfDocumentinfo.h b/src/acbf/AcbfDocumentinfo.h --- a/src/acbf/AcbfDocumentinfo.h +++ b/src/acbf/AcbfDocumentinfo.h @@ -43,6 +43,10 @@ class ACBF_EXPORT DocumentInfo : public QObject { Q_OBJECT + Q_PROPERTY(QStringList authorNames READ authorNames NOTIFY authorsChanged) + Q_PROPERTY(QStringList source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(float version READ version WRITE setVersion NOTIFY versionChanged) + Q_PROPERTY(QStringList history READ history WRITE setHistory NOTIFY historyChanged) public: explicit DocumentInfo(Metadata* parent = nullptr); ~DocumentInfo() override; @@ -75,6 +79,56 @@ */ void removeAuthor(Author* 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 triggers when the authors list changes. + */ + Q_SIGNAL void authorsChanged(); + /** * @return a QDate with the creation date of this file. */ @@ -95,6 +149,16 @@ */ void setSource(const QStringList& source); + /** + * @brief remove the source by index. + * @param index - index of the source to remove. + */ + Q_INVOKABLE void removeSource(int index); + /** + * @brief fires when the source stringlist is changed. + */ + Q_SIGNAL void sourceChanged(); + /** * @returns the unique id of this ACBF document, used for cataloguing purposes. */ @@ -114,7 +178,10 @@ * @param version - the version as a floating point number. */ void setVersion(const float& version); - + /** + * @brief fires when the version of the document changes. + */ + Q_SIGNAL void versionChanged(); /** * @return a list of history entries as a stringlist. */ @@ -129,6 +196,15 @@ * @param historyLine - a single entry in the document. */ void addHistoryLine(const QString& historyLine); + /** + * @brief remove the history line by index. + * @param index - index of the line to remove. + */ + Q_INVOKABLE void removeHistoryLine(int index); + /** + * @brief fires when the history stringlist changes. + */ + Q_SIGNAL void historyChanged(); private: class Private; Private* d; diff --git a/src/acbf/AcbfDocumentinfo.cpp b/src/acbf/AcbfDocumentinfo.cpp --- a/src/acbf/AcbfDocumentinfo.cpp +++ b/src/acbf/AcbfDocumentinfo.cpp @@ -24,6 +24,7 @@ #include #include +#include using namespace AdvancedComicBookFormat; @@ -62,7 +63,7 @@ } writer->writeStartElement(QStringLiteral("creation-date")); - writer->writeCharacters(d->creationDate.toString(QStringLiteral("MMMM d yyyy"))); + writer->writeCharacters(QDate::currentDate().toString(QStringLiteral("MMMM d yyyy"))); writer->writeEndElement(); writer->writeStartElement(QStringLiteral("source")); @@ -74,11 +75,11 @@ writer->writeEndElement(); writer->writeStartElement(QStringLiteral("id")); - writer->writeCharacters(d->id); + writer->writeCharacters(id()); writer->writeEndElement(); writer->writeStartElement(QStringLiteral("version")); - writer->writeCharacters(QString::number(d->version)); + writer->writeCharacters(QString::number(double(d->version))); writer->writeEndElement(); writer->writeStartElement(QStringLiteral("history")); @@ -172,6 +173,55 @@ d->author.removeAll(author); } +QStringList DocumentInfo::authorNames() const +{ + QStringList names; + for(Author* author : d->author) { + names.append(author->displayName()); + } + return names; +} + +Author *DocumentInfo::getAuthor(int index) const +{ + return d->author.at(index); +} + +void DocumentInfo::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 DocumentInfo::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 DocumentInfo::removeAuthor(int index) +{ + removeAuthor(d->author.at(index)); + emit authorsChanged(); +} + QDate DocumentInfo::creationDate() const { return d->creationDate; @@ -190,10 +240,21 @@ void DocumentInfo::setSource(const QStringList& source) { d->source = source; + emit sourceChanged(); +} + +void DocumentInfo::removeSource(int index) +{ + d->source.removeAt(index); + emit sourceChanged(); } QString DocumentInfo::id() const { + // If ID is empty we ought to generate one. + if (d->id.isEmpty()) { + d->id = QUuid::createUuid().toString(); + } return d->id; } @@ -210,6 +271,7 @@ void DocumentInfo::setVersion(const float& version) { d->version = version; + emit versionChanged(); } QStringList DocumentInfo::history() const @@ -220,9 +282,17 @@ void DocumentInfo::setHistory(const QStringList& history) { d->history = history; + emit historyChanged(); } void DocumentInfo::addHistoryLine(const QString& historyLine) { d->history.append(historyLine); + emit historyChanged(); +} + +void DocumentInfo::removeHistoryLine(int index) +{ + d->history.removeAt(index); + emit historyChanged(); } diff --git a/src/acbf/AcbfFrame.h b/src/acbf/AcbfFrame.h --- a/src/acbf/AcbfFrame.h +++ b/src/acbf/AcbfFrame.h @@ -28,6 +28,7 @@ #include "AcbfPage.h" #include +#include /** * \brief a Class to handle comic panels. * @@ -46,7 +47,9 @@ class ACBF_EXPORT Frame : public QObject { Q_OBJECT - + Q_PROPERTY(QString bgcolor READ bgcolor WRITE setBgcolor NOTIFY bgcolorChanged) + Q_PROPERTY(int pointCount READ pointCount NOTIFY pointCountChanged) + Q_PROPERTY(QRect bounds READ bounds NOTIFY boundsChanged) public: explicit Frame(Page* parent = nullptr); ~Frame() override; @@ -69,12 +72,12 @@ * @param index - the index of the desired point. * @return a point for an index. */ - QPoint point(int index) const; + Q_INVOKABLE QPoint point(int index) const; /** * @param point - a point from the points list. * @return the index of the given point. */ - int pointIndex(const QPoint& point) const; + Q_INVOKABLE int pointIndex(const QPoint& point) const; /** * \brief add a point to the points list. @@ -82,18 +85,39 @@ * @param index - the index to add it at. If afterIndex is larger than zero, * the insertion will happen at that index */ - void addPoint(const QPoint& point, int index = -1); + Q_INVOKABLE void addPoint(const QPoint& point, int index = -1); /** * \brief remove a point from the list. * @param point - point to remove from the list. */ - void removePoint(const QPoint& point); + Q_INVOKABLE void removePoint(const QPoint& point); /** * \brief Swap two points in the list. * @param swapThis - the first points to swap. * @param withThis - the second points to swap. */ bool swapPoints(const QPoint& swapThis, const QPoint& withThis); + /** + * @brief set the points based on a top left and bottom right. + * @param topLeft the topleft corner of the rect. + * @param bottomRight the bottomright corner of the rect. + */ + Q_INVOKABLE void setPointsFromRect(const QPoint& topLeft, const QPoint& bottomRight); + + int pointCount() const; + /** + * @brief fires when the point counts changes. + */ + Q_SIGNAL void pointCountChanged(); + /** + * @brief convenience function to get the ractangle of the points. + * @return the bounds of the frame. + */ + QRect bounds() const; + /** + * @brief fires when the bounds change, which happens when the point count changes. + */ + Q_SIGNAL void boundsChanged(); /** * @return the background color as a QString. * @@ -106,6 +130,10 @@ * @param newColor - a String with an 8bit per channel rgb hexcode (#ff00ff, or the like) */ void setBgcolor(const QString& newColor = QString()); + /** + * @brief fires when the background color changes. + */ + Q_SIGNAL void bgcolorChanged(); private: class Private; diff --git a/src/acbf/AcbfFrame.cpp b/src/acbf/AcbfFrame.cpp --- a/src/acbf/AcbfFrame.cpp +++ b/src/acbf/AcbfFrame.cpp @@ -38,6 +38,8 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("Frame*"); + connect(this, SIGNAL(pointCountChanged()), this, SIGNAL(boundsChanged())); } Frame::~Frame() = default; @@ -106,11 +108,13 @@ else { d->points.append(point); } + emit pointCountChanged(); } void Frame::removePoint(const QPoint& point) { d->points.removeAll(point); + emit pointCountChanged(); } bool Frame::swapPoints(const QPoint& swapThis, const QPoint& withThis) @@ -119,11 +123,50 @@ int index2 = d->points.indexOf(withThis); if(index1 > -1 && index2 > -1) { d->points.swap(index1, index2); + emit pointCountChanged(); return true; } return false; } +void Frame::setPointsFromRect(const QPoint &topLeft, const QPoint &bottomRight) +{ + QRect rect(topLeft, bottomRight); + d->points.clear(); + d->points.append(topLeft); + d->points.append(rect.topRight()); + d->points.append(rect.bottomRight()); + d->points.append(rect.bottomLeft()); + emit pointCountChanged(); +} + +int Frame::pointCount() const +{ + return d->points.size(); +} + +QRect Frame::bounds() const +{ + // Would use QPolygon here, but that requires including QTGUI. + QRect rect(d->points.at(0), d->points.at(1)); + for (int i = 2; i < d->points.size(); i++) { + QPoint p = d->points.at(i); + if (rect.left() > p.x()) { + rect.setLeft(p.x()); + } + if (rect.right() < p.x()) { + rect.setRight(p.x()); + } + if (rect.bottom() < p.y()) { + rect.setBottom(p.y()); + } + if (rect.top() > p.y()) { + rect.setTop(p.y()); + } + } + return rect; +} + QString Frame::bgcolor() const { return d->bgcolor; @@ -132,4 +175,5 @@ void Frame::setBgcolor(const QString& newColor) { d->bgcolor = newColor; + emit bgcolorChanged(); } diff --git a/src/acbf/AcbfJump.h b/src/acbf/AcbfJump.h --- a/src/acbf/AcbfJump.h +++ b/src/acbf/AcbfJump.h @@ -28,6 +28,7 @@ #include "AcbfPage.h" #include +#include namespace AdvancedComicBookFormat { /** @@ -48,6 +49,9 @@ class ACBF_EXPORT Jump : public QObject { Q_OBJECT + Q_PROPERTY(int pointCount READ pointCount NOTIFY pointCountChanged) + Q_PROPERTY(QRect bounds READ bounds NOTIFY boundsChanged) + Q_PROPERTY(int pageIndex READ pageIndex WRITE setPageIndex NOTIFY pageIndexChanged) public: explicit Jump(Page* parent = nullptr); @@ -71,12 +75,12 @@ * @param index - the index of the desired point. * @return a point for an index. */ - QPoint point(int index) const; + Q_INVOKABLE QPoint point(int index) const; /** * @param point - a point from the points list. * @return the index of the given point. */ - int pointIndex(const QPoint& point) const; + Q_INVOKABLE int pointIndex(const QPoint& point) const; /** * \brief add a point to the points list. @@ -84,19 +88,39 @@ * @param index - the index to add it at. If afterIndex is larger than zero, * the insertion will happen at that index */ - void addPoint(const QPoint& point, int index = -1); + Q_INVOKABLE void addPoint(const QPoint& point, int index = -1); /** * \brief remove a point from the list. * @param point - point to remove from the list. */ - void removePoint(const QPoint& point); + Q_INVOKABLE void removePoint(const QPoint& point); /** * \brief Swap two points in the list. * @param swapThis - the first points to swap. * @param withThis - the second points to swap. */ bool swapPoints(const QPoint& swapThis, const QPoint& withThis); - + /** + * @brief set the points based on a top left and bottom right. + * @param topLeft the topleft corner of the rect. + * @param bottomRight the bottomright corner of the rect. + */ + Q_INVOKABLE void setPointsFromRect(const QPoint& topLeft, const QPoint& bottomRight); + + int pointCount() const; + /** + * @brief fires when the point counts changes. + */ + Q_SIGNAL void pointCountChanged(); + /** + * @brief convenience function to get the ractangle of the points. + * @return the bounds of the frame. + */ + QRect bounds() const; + /** + * @brief fires when the bounds change, which happens when the point count changes. + */ + Q_SIGNAL void boundsChanged(); /** * @brief The page to jump to. * @@ -111,6 +135,10 @@ * page list. */ void setPageIndex(const int& pageNumber = 0); + /** + * @brief pageIndexChanged + */ + Q_SIGNAL void pageIndexChanged(); private: class Private; diff --git a/src/acbf/AcbfJump.cpp b/src/acbf/AcbfJump.cpp --- a/src/acbf/AcbfJump.cpp +++ b/src/acbf/AcbfJump.cpp @@ -39,6 +39,8 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("Jump*"); + connect(this, SIGNAL(pointCountChanged()), this, SIGNAL(boundsChanged())); } Jump::~Jump() = default; @@ -105,11 +107,13 @@ else { d->points.append(point); } + emit pointCountChanged(); } void Jump::removePoint(const QPoint& point) { d->points.removeAll(point); + emit pointCountChanged(); } bool Jump::swapPoints(const QPoint& swapThis, const QPoint& withThis) @@ -118,11 +122,50 @@ int index2 = d->points.indexOf(withThis); if(index1 > -1 && index2 > -1) { d->points.swap(index1, index2); + emit pointCountChanged(); return true; } return false; } +void Jump::setPointsFromRect(const QPoint &topLeft, const QPoint &bottomRight) +{ + QRect rect(topLeft, bottomRight); + d->points.clear(); + d->points.append(topLeft); + d->points.append(rect.topRight()); + d->points.append(rect.bottomRight()); + d->points.append(rect.bottomLeft()); + emit pointCountChanged(); +} + +int Jump::pointCount() const +{ + return d->points.size(); +} + +QRect Jump::bounds() const +{ + // Would use QPolygon here, but that requires including QTGUI. + QRect rect(d->points.at(0), d->points.at(1)); + for (int i = 2; i < d->points.size(); i++) { + QPoint p = d->points.at(i); + if (rect.left() > p.x()) { + rect.setLeft(p.x()); + } + if (rect.right() < p.x()) { + rect.setRight(p.x()); + } + if (rect.bottom() < p.y()) { + rect.setBottom(p.y()); + } + if (rect.top() > p.y()) { + rect.setTop(p.y()); + } + } + return rect; +} + int Jump::pageIndex() const { return d->pageIndex; @@ -131,4 +174,5 @@ void Jump::setPageIndex(const int& pageNumber) { d->pageIndex = pageNumber; + emit pageIndexChanged(); } diff --git a/src/acbf/AcbfMetadata.h b/src/acbf/AcbfMetadata.h --- a/src/acbf/AcbfMetadata.h +++ b/src/acbf/AcbfMetadata.h @@ -47,6 +47,8 @@ class ACBF_EXPORT Metadata : public QObject { Q_OBJECT Q_PROPERTY(AdvancedComicBookFormat::BookInfo* bookInfo READ bookInfo NOTIFY bookInfoChanged) + Q_PROPERTY(AdvancedComicBookFormat::PublishInfo* publishInfo READ publishInfo NOTIFY publishInfoChanged) + Q_PROPERTY(AdvancedComicBookFormat::DocumentInfo* documentInfo READ documentInfo NOTIFY documentInfoChanged) public: explicit Metadata(Document* parent = nullptr); ~Metadata() override; @@ -75,10 +77,18 @@ * @returns the publishinfo object. */ PublishInfo* publishInfo() const; + /** + * @brief fires when the publishing info changes. + */ + Q_SIGNAL void publishInfoChanged(); /** * @returns the documentinfo object. */ DocumentInfo* documentInfo() const; + /** + * @brief fires when the document info changes. + */ + Q_SIGNAL void documentInfoChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfPage.h b/src/acbf/AcbfPage.h --- a/src/acbf/AcbfPage.h +++ b/src/acbf/AcbfPage.h @@ -57,6 +57,12 @@ class ACBF_EXPORT Page : public QObject { Q_OBJECT + Q_PROPERTY(QString bgcolor READ bgcolor WRITE setBgcolor NOTIFY bgcolorChanged) + Q_PROPERTY(QString transition READ transition WRITE setTransition NOTIFY transitionChanged) + Q_PROPERTY(QString imageHref READ imageHref WRITE setImageHref NOTIFY imageHrefChanged) + Q_PROPERTY(QStringList textLayerLanguages READ textLayerLanguages NOTIFY textLayerLanguagesChanged) + Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged) + Q_PROPERTY(int jumpCount READ jumpCount NOTIFY jumpCountChanged) public: // Pages can also be cover pages, which means they can also be children of BookInfo explicit Page(Document* parent = nullptr); @@ -84,7 +90,10 @@ * @param newColor - a String with an 8bit per channel rgb hexcode (#ff00ff, or the like) */ void setBgcolor(const QString& newColor = QString()); - + /** + * @brief fires when the background color changes. + */ + Q_SIGNAL void bgcolorChanged(); /** * @return transition type as a string. */ @@ -94,27 +103,35 @@ * @param transition - the transition type, possible entries are in the availableTransitions() stringlist. */ void setTransition(const QString& transition); + /** + * @brief fires when the transition type changes. + */ + Q_SIGNAL void transitionChanged(); /** * @returns a list of strings that can be used for the transition. */ - static QStringList availableTransitions(); + Q_INVOKABLE static QStringList availableTransitions(); /** * @return all titles for this page in all languages. */ - QStringList titleForAllLanguages() const; + Q_INVOKABLE QStringList titleForAllLanguages() const; /** * @param language - the language of the entry in language code, country * code format joined by a dash (not an underscore). * @return the title for this language. */ - QString title(const QString& language = QString()) const; + Q_INVOKABLE QString title(const QString& language = QString()) const; /** * \brief set the title for this language. * @param language - the language of the entry in language code, country * code format joined by a dash (not an underscore). */ - void setTitle(const QString& title, const QString& language = QString()); + Q_INVOKABLE void setTitle(const QString& title, const QString& language = QString()); + /** + * @brief titlesChanged + */ + Q_SIGNAL void titlesChanged(); /** * @returns the URI for the image of this page as a QString @@ -130,6 +147,10 @@ * - Everything else is presumed to be a file on disk. */ void setImageHref(const QString& imageHref); + /** + * @brief fires when the image url changes. + */ + Q_SIGNAL void imageHrefChanged(); /** * @returns all the textlayers objects. @@ -140,7 +161,7 @@ * code format joined by a dash (not an underscore). * @returns the TextLayer object for that language. */ - Textlayer* textLayer(const QString& language = QString()) const; + Q_INVOKABLE Textlayer* textLayer(const QString& language = QString()) const; /** * * @param language - the language of the entry in language code, country @@ -148,7 +169,35 @@ * for a language to null removes that language (as with other translated * entries, though this one not being text warranted a comment) */ - void setTextLayer(Textlayer* textlayer, const QString& language = ""); + void setTextLayer(Textlayer* textlayer, const QString& language = QString()); + /** + * @brief add a textlayer for language. + * @param language code to add a textlayer for. + */ + Q_INVOKABLE void addTextLayer(const QString& language = QString()); + /** + * @brief remove a text layer by language. + * @param language code to remove the textlayer for. + */ + Q_INVOKABLE void removeTextLayer(const QString& language = QString()); + /** + * @brief duplicate a text layer to a different language, if languageFrom doesn't + * exist this makes a new text layer. + * @param languageFrom the language from which to duplicate. + * @param languageTo the language to make the new text layer at. + */ + Q_INVOKABLE void duplicateTextLayer(const QString&languageFrom, const QString& languageTo = QString()); + /** + * @brief get the possible translations. + * @return a stringlist with all the languages available. + */ + QStringList textLayerLanguages() const; + /** + * @brief fires when the textlayer languages list changes + * + * this can happen when text layers are added or removed. + */ + Q_SIGNAL void textLayerLanguagesChanged(); /** * @returns a list of frames in this page. @@ -158,7 +207,7 @@ * @param index - index of the frame. * @return the frame of that index. */ - Frame* frame(int index) const; + Q_INVOKABLE Frame* frame(int index) const; /** * @param frame - the frame you want to index of. * @returns the index of the given frame. @@ -177,12 +226,32 @@ * @param frame - the frame to remove. */ void removeFrame(Frame* frame); + /** + * @brief remove frame by index. + * @param index index of the frame to remove. + */ + Q_INVOKABLE void removeFrame(int index); + /** + * @brief add a frame at index.. + * @param index - the index to add it at. If afterIndex is larger than + * zero, the insertion will happen at that index + */ + Q_INVOKABLE void addFrame(int index = -1); /** * \brief Swap two frames in the list. - * @param swapThis - the first frame to swap. - * @param withThis - the second frame to swap. + * @param swapThis - the first index to swap. + * @param withThis - the second index to swap. */ - bool swapFrames(Frame* swapThis, Frame* withThis); + Q_INVOKABLE bool swapFrames(int swapThis, int withThis); + /** + * @brief frameCount + * @return the total amount of frames. + */ + int frameCount(); + /** + * @brief fires when the frame count changes. + */ + Q_SIGNAL void frameCountChanged(); /** * @return the list of jump objects for this page. @@ -192,7 +261,7 @@ * @param index - the index for which you want the jump object. * @return a jump object for the given frame. */ - Jump* jump(int index) const; + Q_INVOKABLE Jump* jump(int index) const; /** * @param jump - the jump you want to index of. * @returns the index of the given jump. @@ -206,17 +275,36 @@ * zero, the insertion will happen at that index */ void addJump(Jump* jump, int index = -1); + /** + * @brief addJump + * @param index - the index to add it at. If afterIndex is larger than + * zero, the insertion will happen at that index + */ + Q_INVOKABLE void addJump(int pageIndex, int index = -1); /** * \brief remove the given jump from the list of jumps. * @param jump - the jump to remove. */ void removeJump(Jump* jump); + /** + * @brief removeJump + * @param index to remove the jump at. + */ + Q_INVOKABLE void removeJump(int index); /** * \brief Swap two jumps in the list. - * @param swapThis - the first jumps to swap. - * @param withThis - the second jumps to swap. + * @param swapThis - the first index to swap. + * @param withThis - the second index to swap. + */ + Q_INVOKABLE bool swapJumps(int swapThis, int withThis); + /** + * @brief the amount of jumps on this page. + */ + int jumpCount(); + /** + * @brief changes when the jumpcount changes. */ - bool swapJumps(Jump* swapThis, Jump* withThis); + Q_SIGNAL void jumpCountChanged(); /** * @returns whether this is the cover page. diff --git a/src/acbf/AcbfPage.cpp b/src/acbf/AcbfPage.cpp --- a/src/acbf/AcbfPage.cpp +++ b/src/acbf/AcbfPage.cpp @@ -23,6 +23,7 @@ #include "AcbfTextlayer.h" #include "AcbfFrame.h" #include "AcbfJump.h" +#include "AcbfTextarea.h" #include #include @@ -50,6 +51,7 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("Page*"); } Page::~Page() = default; @@ -170,6 +172,7 @@ void Page::setBgcolor(const QString& newColor) { d->bgcolor = newColor; + emit bgcolorChanged(); } QString Page::transition() const @@ -180,6 +183,7 @@ void Page::setTransition(const QString& transition) { d->transition = transition; + emit transitionChanged(); } QStringList Page::availableTransitions() @@ -200,7 +204,20 @@ QString Page::title(const QString& language) const { - return d->title.value(language); + if (d->title.count()==0) { + return ""; + } + if (!d->title.keys().contains(language)) { + d->title.values().at(0); + } + + QString title = d->title.value(language); + + if (title.isEmpty()) { + title = d->title.values().at(0); + } + + return title; } void Page::setTitle(const QString& title, const QString& language) @@ -213,6 +230,7 @@ { d->title[language] = title; } + emit titlesChanged(); } QString Page::imageHref() const @@ -232,6 +250,9 @@ Textlayer * Page::textLayer(const QString& language) const { + if (!d->textLayers.keys().contains("") && language == QString()) { + return d->textLayers.values().at(0); + } return d->textLayers.value(language); } @@ -245,6 +266,50 @@ { d->textLayers.remove(language); } + emit textLayerLanguagesChanged(); +} + +void Page::addTextLayer(const QString &language) +{ + Textlayer* textLayer = new Textlayer(this); + textLayer->setLanguage(language); + setTextLayer(textLayer, language); +} + +void Page::removeTextLayer(const QString &language) +{ + setTextLayer(nullptr, language); +} + +void Page::duplicateTextLayer(const QString &languageFrom, const QString &languageTo) +{ + Textlayer* to = new Textlayer(this); + to->setLanguage(languageTo); + if (d->textLayers[languageFrom]) { + Textlayer* from = d->textLayers[languageFrom]; + to->setBgcolor(from->bgcolor()); + for (int i=0; itextareaCount(); i++) { + to->addTextarea(i); + to->textarea(i)->setBgcolor(from->textarea(i)->bgcolor()); + to->textarea(i)->setInverted(from->textarea(i)->inverted()); + to->textarea(i)->setTransparent(from->textarea(i)->transparent()); + to->textarea(i)->setTextRotation(from->textarea(i)->textRotation()); + to->textarea(i)->setType(from->textarea(i)->type()); + to->textarea(i)->setParagraphs(from->textarea(i)->paragraphs()); + for (int p=0; ptextarea(i)->pointCount(); p++) { + to->textarea(i)->addPoint(from->textarea(i)->point(p)); + } + } + } + setTextLayer(to); +} + +QStringList Page::textLayerLanguages() const +{ + if (d->textLayers.isEmpty()) { + return QStringList(); + } + return d->textLayers.keys(); } QList Page::frames() const @@ -270,24 +335,41 @@ else { d->frames.append(frame); } + emit frameCountChanged(); } void Page::removeFrame(Frame* frame) { d->frames.removeAll(frame); + emit frameCountChanged(); +} + +void Page::removeFrame(int index) +{ + removeFrame(frame(index)); } -bool Page::swapFrames(Frame* swapThis, Frame* withThis) +void Page::addFrame(int index) { - int index1 = d->frames.indexOf(swapThis); - int index2 = d->frames.indexOf(withThis); - if(index1 > -1 && index2 > -1) { - d->frames.swap(index1, index2); + Frame* frame = new Frame(this); + addFrame(frame, index); +} + +bool Page::swapFrames(int swapThis, int withThis) +{ + if(swapThis > -1 && withThis > -1) { + d->frames.swap(swapThis, withThis); + emit frameCountChanged(); return true; } return false; } +int Page::frameCount() +{ + return d->frames.size(); +} + QList Page::jumps() const { return d->jumps; @@ -311,24 +393,42 @@ else { d->jumps.append(jump); } + emit jumpCountChanged(); +} + +void Page::addJump(int pageIndex, int index) +{ + Jump* jump = new Jump(this); + jump->setPageIndex(pageIndex); + addJump(jump, index); } void Page::removeJump(Jump* jump) { d->jumps.removeAll(jump); + emit jumpCountChanged(); +} + +void Page::removeJump(int index) +{ + removeJump(jump(index)); } -bool Page::swapJumps(Jump* swapThis, Jump* withThis) +bool Page::swapJumps(int swapThis, int withThis) { - int index1 = d->jumps.indexOf(swapThis); - int index2 = d->jumps.indexOf(withThis); - if(index1 > -1 && index2 > -1) { - d->jumps.swap(index1, index2); + if(swapThis > -1 && withThis > -1) { + d->jumps.swap(swapThis, withThis); + emit jumpCountChanged(); return true; } return false; } +int Page::jumpCount() +{ + return d->jumps.size(); +} + bool Page::isCoverPage() const { return d->isCoverPage; diff --git a/src/acbf/AcbfPublishinfo.h b/src/acbf/AcbfPublishinfo.h --- a/src/acbf/AcbfPublishinfo.h +++ b/src/acbf/AcbfPublishinfo.h @@ -39,6 +39,11 @@ class ACBF_EXPORT PublishInfo : public QObject { Q_OBJECT + Q_PROPERTY(QString publisher READ publisher WRITE setPublisher NOTIFY publisherChanged) + Q_PROPERTY(QDate publishDate READ publishDate WRITE setPublishDate NOTIFY publishDateChanged) + Q_PROPERTY(QString city READ city WRITE setCity NOTIFY cityChanged) + Q_PROPERTY(QString isbn READ isbn WRITE setIsbn NOTIFY isbnChanged) + Q_PROPERTY(QString license READ license WRITE setLicense NOTIFY licenseChanged) public: explicit PublishInfo(Metadata* parent = nullptr); ~PublishInfo() override; @@ -61,6 +66,10 @@ * \brief set the name of the publisher. */ void setPublisher(const QString& publisher); + /** + * @brief fires when the publisher has changed. + */ + Q_SIGNAL void publisherChanged(); /** * @return the publishing date as a QDate object. @@ -71,6 +80,17 @@ * @param publishDate - the publishingdate as a QDate object. */ void setPublishDate(const QDate& publishDate); + /** + * @brief a function to work around strangeness surrounding qml date. + * @param year - publishing year. + * @param month - publishing month, from 1 to 12 + * @param day - publishing day. + */ + Q_INVOKABLE void setPublishDateFromInts(const int& year, const int& month, const int& day); + /** + * @brief fires when the date has changed. + */ + Q_SIGNAL void publishDateChanged(); /** * @return the name of the city the work was published in. @@ -81,6 +101,10 @@ * @param city - the name of the city as a QString. */ void setCity(const QString& city = QString()); + /** + * @brief fires when the city has changed. + */ + Q_SIGNAL void cityChanged(); /** * @return the ISBN number as a QString. @@ -91,6 +115,10 @@ * @param isbn - the ISBN number as a QString. ISBN numbers should be registered. */ void setIsbn(const QString& isbn = QString()); + /** + * @brief fires when the usbn has changed. + */ + Q_SIGNAL void isbnChanged(); /** * @return the name of the license the comic was published under. @@ -101,6 +129,10 @@ * @param license - the name of the license as a QString. */ void setLicense(const QString& license = QString()); + /** + * @brief fires when the license has changed. + */ + Q_SIGNAL void licenseChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfPublishinfo.cpp b/src/acbf/AcbfPublishinfo.cpp --- a/src/acbf/AcbfPublishinfo.cpp +++ b/src/acbf/AcbfPublishinfo.cpp @@ -56,7 +56,7 @@ writer->writeEndElement(); writer->writeStartElement(QStringLiteral("publish-date")); - writer->writeAttribute(QStringLiteral("value"), d->publishDate.toString(QStringLiteral("YYYY-MM-dd"))); + writer->writeAttribute(QStringLiteral("value"), d->publishDate.toString(QStringLiteral("yyyy-MM-dd"))); writer->writeCharacters(d->publishDate.toString(QStringLiteral("MMMM d yyyy"))); writer->writeEndElement(); @@ -86,12 +86,13 @@ else if(xmlReader->name() == QStringLiteral("publish-date")) { QString date = xmlReader->attributes().value(QStringLiteral("value")).toString(); - if(date.isEmpty()) { + if(date.isEmpty() || !QDate::fromString(date, Qt::ISODate).isValid()) { date = xmlReader->readElementText(); + setPublishDate(QDate::fromString(date)); } else { + setPublishDate(QDate::fromString(date, Qt::ISODate)); xmlReader->skipCurrentElement(); } - setPublishDate(QDate::fromString(date)); } else if(xmlReader->name() == QStringLiteral("city")) { @@ -126,16 +127,28 @@ void PublishInfo::setPublisher(const QString& publisher) { d->publisher = publisher; + emit publisherChanged(); } QDate PublishInfo::publishDate() const { - return d->publishDate; + if (d->publishDate.isValid()) { + return d->publishDate; + } else { + return QDate().currentDate(); + } } void PublishInfo::setPublishDate(const QDate& publishDate) { d->publishDate = publishDate; + emit publishDateChanged(); +} + +void PublishInfo::setPublishDateFromInts(const int &year, const int &month, const int &day) +{ + QDate date(year, month, day); + setPublishDate(date); } QString PublishInfo::city() const @@ -146,6 +159,7 @@ void PublishInfo::setCity(const QString& city) { d->city = city; + emit cityChanged(); } QString PublishInfo::isbn() const @@ -156,6 +170,7 @@ void PublishInfo::setIsbn(const QString& isbn) { d->isbn = isbn; + emit isbnChanged(); } QString PublishInfo::license() const @@ -166,4 +181,5 @@ void PublishInfo::setLicense(const QString& license) { d->license = license; + emit licenseChanged(); } diff --git a/src/acbf/AcbfSequence.h b/src/acbf/AcbfSequence.h --- a/src/acbf/AcbfSequence.h +++ b/src/acbf/AcbfSequence.h @@ -37,6 +37,9 @@ class ACBF_EXPORT Sequence : public QObject { Q_OBJECT + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(int number READ number WRITE setNumber NOTIFY numberChanged) public: explicit Sequence(BookInfo * parent = nullptr); ~Sequence() override; @@ -61,6 +64,8 @@ */ void setTitle(const QString& title); + Q_SIGNAL void titleChanged(); + /** * @returns the volume number. */ @@ -72,6 +77,8 @@ */ void setVolume(int volume = 0); + Q_SIGNAL void volumeChanged(); + /** * @return the number that this work takes up in the sequence. */ @@ -82,6 +89,8 @@ * part of the series. */ void setNumber(int number); + + Q_SIGNAL void numberChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfSequence.cpp b/src/acbf/AcbfSequence.cpp --- a/src/acbf/AcbfSequence.cpp +++ b/src/acbf/AcbfSequence.cpp @@ -42,6 +42,7 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("Sequence*"); } Sequence::~Sequence() = default; @@ -72,6 +73,7 @@ void Sequence::setTitle(const QString& title) { d->title = title; + emit titleChanged(); } int Sequence::volume() const @@ -82,6 +84,7 @@ void Sequence::setVolume(int volume) { d->volume = volume; + emit volumeChanged(); } int Sequence::number() const @@ -92,4 +95,5 @@ void Sequence::setNumber(int number) { d->number = number; + emit numberChanged(); } diff --git a/src/acbf/AcbfTextarea.h b/src/acbf/AcbfTextarea.h --- a/src/acbf/AcbfTextarea.h +++ b/src/acbf/AcbfTextarea.h @@ -27,6 +27,7 @@ #include "AcbfTextlayer.h" #include +#include /** * \brief Class to handle the text areas in ACBF @@ -40,6 +41,15 @@ class ACBF_EXPORT Textarea : public QObject { Q_OBJECT + Q_PROPERTY(QString bgcolor READ bgcolor WRITE setBgcolor NOTIFY bgcolorChanged) + Q_PROPERTY(int pointCount READ pointCount NOTIFY pointCountChanged) + Q_PROPERTY(QRect bounds READ bounds NOTIFY boundsChanged) + Q_PROPERTY(int textRotation READ textRotation WRITE setTextRotation NOTIFY textRotationChanged) + Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged) + Q_PROPERTY(bool inverted READ inverted WRITE setInverted NOTIFY invertedChanged) + Q_PROPERTY(bool transparent READ transparent WRITE setTransparent NOTIFY transparentChanged) + Q_PROPERTY(QStringList paragraphs READ paragraphs WRITE setParagraphs NOTIFY paragraphsChanged) + public: explicit Textarea(Textlayer* parent = nullptr); ~Textarea() override; @@ -67,12 +77,12 @@ * @param index - the index of the desired point. * @return a point for an index. */ - QPoint point(int index) const; + Q_INVOKABLE QPoint point(int index) const; /** * @param point - a point from the points list. * @return the index of the given point. */ - int pointIndex(const QPoint& point) const; + Q_INVOKABLE int pointIndex(const QPoint& point) const; /** * \brief add a point to the points list. @@ -80,19 +90,39 @@ * @param index - the index to add it at. If afterIndex is larger than zero, * the insertion will happen at that index */ - void addPoint(const QPoint& point, int index = -1); + Q_INVOKABLE void addPoint(const QPoint& point, int index = -1); /** * \brief remove a point from the list. * @param point - point to remove from the list. */ - void removePoint(const QPoint& point); + Q_INVOKABLE void removePoint(const QPoint& point); /** * \brief Swap two points in the list. * @param swapThis - the first points to swap. * @param withThis - the second points to swap. */ bool swapPoints(const QPoint& swapThis, const QPoint& withThis); + /** + * @brief set the points based on a top left and bottom right. + * @param topLeft the topleft corner of the rect. + * @param bottomRight the bottomright corner of the rect. + */ + Q_INVOKABLE void setPointsFromRect(const QPoint& topLeft, const QPoint& bottomRight); + int pointCount() const; + /** + * @brief fires when the point counts changes. + */ + Q_SIGNAL void pointCountChanged(); + /** + * @brief convenience function to get the ractangle of the points. + * @return the bounds of the frame. + */ + QRect bounds() const; + /** + * @brief fires when the bounds change, which happens when the point count changes. + */ + Q_SIGNAL void boundsChanged(); /** * @return the background color as a QString. * @@ -105,6 +135,10 @@ * @param newColor - a String with an 8bit per channel rgb hexcode (#ff00ff, or the like) */ void setBgcolor(const QString& newColor = QString()); + /** + * @brief fires when the background color changes. + */ + Q_SIGNAL void bgcolorChanged(); /** * @return the text rotation in degrees. @@ -115,6 +149,10 @@ * @param rotation - the text rotation in degrees. */ void setTextRotation(int rotation = 0); + /** + * @brief fires when the text rotation is set. + */ + Q_SIGNAL void textRotationChanged(); /** * @return the type of the text area. This determines how it is styled. @@ -126,6 +164,10 @@ * it will change the way how the text is styled. The default is "speech". */ void setType(const QString& type = QStringLiteral("speech")); + /** + * @brief fires when the type is set. + */ + Q_SIGNAL void typeChanged(); /** * @return whether the text should use the 'inverted' colorscheme. @@ -136,7 +178,10 @@ * @param inverted - whether to do so. */ void setInverted(bool inverted = false); - + /** + * @brief fires when inverted is set. + */ + Q_SIGNAL void invertedChanged(); /** * @return whether to use the background color when overlaying the text. */ @@ -147,6 +192,10 @@ * to have the textare background transparent. */ void setTransparent(bool transparent = false); + /** + * @brief fires when transparent is set. + */ + Q_SIGNAL void transparentChanged(); /** * @returns a list of paragraphs. @@ -163,6 +212,10 @@ * strong, emphasis, strikethrough, sub, sup, a (with mandatory href attribute only) */ void setParagraphs(const QStringList& paragraphs); + /** + * @brief fires when the paragraphs are set. + */ + Q_SIGNAL void paragraphsChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfTextarea.cpp b/src/acbf/AcbfTextarea.cpp --- a/src/acbf/AcbfTextarea.cpp +++ b/src/acbf/AcbfTextarea.cpp @@ -45,6 +45,8 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("Textarea*"); + connect(this, SIGNAL(pointCountChanged()), this, SIGNAL(boundsChanged())); } Textarea::~Textarea() = default; @@ -150,11 +152,13 @@ else { d->points.append(point); } + emit pointCountChanged(); } void Textarea::removePoint(const QPoint& point) { d->points.removeAll(point); + emit pointCountChanged(); } bool Textarea::swapPoints(const QPoint& swapThis, const QPoint& withThis) @@ -163,10 +167,48 @@ int index2 = d->points.indexOf(withThis); if(index1 > -1 && index2 > -1) { d->points.swap(index1, index2); + emit pointCountChanged(); return true; } return false; } +void Textarea::setPointsFromRect(const QPoint &topLeft, const QPoint &bottomRight) +{ + QRect rect(topLeft, bottomRight); + d->points.clear(); + d->points.append(topLeft); + d->points.append(rect.topRight()); + d->points.append(rect.bottomRight()); + d->points.append(rect.bottomLeft()); + emit pointCountChanged(); +} + +int Textarea::pointCount() const +{ + return d->points.size(); +} + +QRect Textarea::bounds() const +{ + // Would use QPolygon here, but that requires including QTGUI. + QRect rect(d->points.at(0), d->points.at(1)); + for (int i = 2; i < d->points.size(); i++) { + QPoint p = d->points.at(i); + if (rect.left() > p.x()) { + rect.setLeft(p.x()); + } + if (rect.right() < p.x()) { + rect.setRight(p.x()); + } + if (rect.bottom() < p.y()) { + rect.setBottom(p.y()); + } + if (rect.top() > p.y()) { + rect.setTop(p.y()); + } + } + return rect; +} QString Textarea::bgcolor() const { @@ -176,11 +218,13 @@ void Textarea::setBgcolor(const QString& newColor) { d->bgcolor = newColor; + emit bgcolorChanged(); } void Textarea::setTextRotation(int rotation) { d->textRotation = rotation; + emit textRotationChanged(); } int Textarea::textRotation() const @@ -196,6 +240,7 @@ void Textarea::setType(const QString& type) { d->type = type; + emit typeChanged(); } QStringList Textarea::availableTypes() @@ -222,6 +267,7 @@ void Textarea::setInverted(bool inverted) { d->inverted = inverted; + emit invertedChanged(); } bool Textarea::transparent() const @@ -232,6 +278,7 @@ void Textarea::setTransparent(bool transparent) { d->transparent = transparent; + emit transparentChanged(); } QStringList Textarea::paragraphs() const @@ -242,4 +289,5 @@ void Textarea::setParagraphs(const QStringList& paragraphs) { d->paragraphs = paragraphs; + emit paragraphsChanged(); } diff --git a/src/acbf/AcbfTextlayer.h b/src/acbf/AcbfTextlayer.h --- a/src/acbf/AcbfTextlayer.h +++ b/src/acbf/AcbfTextlayer.h @@ -39,6 +39,9 @@ class ACBF_EXPORT Textlayer : public QObject { Q_OBJECT + Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged) + Q_PROPERTY(QString bgcolor READ bgcolor WRITE setBgcolor NOTIFY bgcolorChanged) + Q_PROPERTY(int textareaCount READ textareaCount NOTIFY textareaCountChanged) public: explicit Textlayer(Page* parent = nullptr); ~Textlayer() override; @@ -63,6 +66,10 @@ * code format joined by a dash (not an underscore). */ void setLanguage(const QString& language); + /** + * @brief fires when the language changes. + */ + Q_SIGNAL void languageChanged(); /** * @return the background color as a QString. @@ -76,6 +83,10 @@ * @param newColor - a String with an 8bit per channel rgb hexcode (#ff00ff, or the like) */ void setBgcolor(const QString& newColor = QString()); + /** + * @brief fires when the background color changes. + */ + Q_SIGNAL void bgcolorChanged(); /** * @returns a list of textareas in this page. @@ -85,31 +96,51 @@ * @param index - index of the textarea. * @return the textarea of that index. */ - Textarea* textarea(int index) const; + Q_INVOKABLE Textarea* textarea(int index) const; /** * @param textarea - the textarea you want to index of. * @returns the index of the given textarea. */ - int textareaIndex(Textarea* textarea) const; + Q_INVOKABLE int textareaIndex(Textarea* textarea) const; /** * \brief add a textarea to the list of frames. - * @param textarea - the frame to add. + * @param textarea - the textarea to add. * @param index - the index to add it at. If afterIndex is larger than * zero, the insertion will happen at that index */ void addTextarea(Textarea* textarea, int index = -1); + /** + * @brief add a text area at index. + * @param index - the index to add it at. If afterIndex is larger than + * zero, the insertion will happen at that index + */ + Q_INVOKABLE void addTextarea(int index = -1); /** * \brief remove the given textarea from the framelist. * @param textarea - the textarea to remove. */ void removeTextarea(Textarea* textarea); + /** + * @brief addTextarea + * @param index to remove the textarea at. + */ + Q_INVOKABLE void removeTextarea(int index); /** * \brief Swap two textareas in the list. * @param swapThis - the first textarea to swap. * @param withThis - the second textarea to swap. */ - bool swapTextareas(Textarea* swapThis, Textarea* withThis); + Q_INVOKABLE bool swapTextareas(int swapThis, int withThis); + /** + * @brief textareaCount + * @return + */ + int textareaCount(); + /** + * @brief textareaCountChanged + */ + Q_SIGNAL void textareaCountChanged(); private: class Private; std::unique_ptr d; diff --git a/src/acbf/AcbfTextlayer.cpp b/src/acbf/AcbfTextlayer.cpp --- a/src/acbf/AcbfTextlayer.cpp +++ b/src/acbf/AcbfTextlayer.cpp @@ -41,6 +41,7 @@ : QObject(parent) , d(new Private) { + qRegisterMetaType("Textlayer*"); } Textlayer::~Textlayer() = default; @@ -97,6 +98,7 @@ void Textlayer::setLanguage(const QString& language) { d->language = language; + emit languageChanged(); } QString Textlayer::bgcolor() const @@ -107,6 +109,7 @@ void Textlayer::setBgcolor(const QString& newColor) { d->bgcolor = newColor; + emit bgcolorChanged(); } QList