File indexing completed on 2025-01-26 04:14:58

0001 /*
0002  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 #ifndef ARCHIVEBOOKMODEL_H
0023 #define ARCHIVEBOOKMODEL_H
0024 
0025 #include "BookModel.h"
0026 #include <QMutex>
0027 /**
0028  * \brief Class to hold pages and metadata for archive based books.
0029  * 
0030  * In particular, ArchiveBookModel handles CBZ and CBR files, reads
0031  * potential metadata and holds that into the acbfdata object.
0032  * 
0033  * ArchiveBookModel extends BookModel, which handles the functions for
0034  * setting the current page, and returning basic metadata.
0035  */
0036 class KArchiveFile;
0037 class ArchiveBookModel : public BookModel
0038 {
0039     Q_OBJECT
0040     Q_PROPERTY(QObject* qmlEngine READ qmlEngine WRITE setQmlEngine NOTIFY qmlEngineChanged)
0041     Q_PROPERTY(bool readWrite READ readWrite WRITE setReadWrite NOTIFY readWriteChanged)
0042     Q_PROPERTY(bool hasUnsavedChanges READ hasUnsavedChanges NOTIFY hasUnsavedChangesChanged)
0043     Q_PROPERTY(QStringList fileEntries READ fileEntries NOTIFY fileEntriesChanged)
0044     Q_PROPERTY(QStringList fileEntriesToDelete READ fileEntriesToDelete NOTIFY fileEntriesToDeleteChanged)
0045 public:
0046     explicit ArchiveBookModel(QObject* parent = nullptr);
0047     ~ArchiveBookModel() override;
0048 
0049     /**
0050      * \brief Set the filename that points to the archive that describes this book.
0051      */
0052     void setFilename(QString newFilename) override;
0053 
0054     /**
0055      * The author name will be either the default bookmodel author name, or
0056      * if ACBF data is available, the first authorname in the list of ACBF authors.
0057      * 
0058      * @return the author name as a QString.
0059      */
0060     QString author() const override;
0061     /**
0062      * \brief Set the main author's nickname.
0063      * 
0064      * If there is no ACBF data, this will set the author to BookModel's author.
0065      * If there is ACBF data, this will set the nickname entry on the name of the
0066      * first possible author.
0067      * 
0068      * Preferably authors should be added by editing the author list in the bookinfo
0069      * of the ACBF metadata this book holds.
0070      * 
0071      * @param newAuthor The main author's nickname.
0072      */
0073     void setAuthor(QString newAuthor) override;
0074     /**
0075      * @return the name of the publisher as a QString.
0076      */
0077     QString publisher() const override;
0078     /**
0079      * \brief Set the name of the publisher.
0080      * @param newPublisher QString with the name of the publisher.
0081      */
0082     void setPublisher(QString newPublisher) override;
0083     /**
0084      * @return The proper title of this book as a QString.
0085      */
0086     QString title() const override;
0087     /**
0088      * \brief Set the default title of this book.
0089      * @param newTitle The default title of this book as a QString.
0090      */
0091     void setTitle(QString newTitle) override;
0092 
0093     /**
0094      * @return a QQmlEngine associated with this book.
0095      * TODO: What is the QML engine and what is its purpose?
0096      * Used in the cbr.qml
0097      */
0098     QObject* qmlEngine() const;
0099     /**
0100      * \brief Set the QML engine on this book.
0101      * @param newEngine A QQmlEngine object.
0102      */
0103     void setQmlEngine(QObject* newEngine);
0104     /**
0105      * \brief Fires when a new QQmlEngine is set on this book.
0106      */
0107     Q_SIGNAL void qmlEngineChanged();
0108 
0109     /**
0110      * Whether or not this model should function in read/write mode. As this is potentially very expensive,
0111      * this option is disabled by default and must be set explicitly to true.
0112      * @return Whether or not the model is read/write (true) or in read-only mode (false)
0113      */
0114     bool readWrite() const;
0115     /**
0116      * Sets the readWrite option
0117      * @see readWrite()
0118      * @param newReadWrite Whether or not the model should be read/write (true) or in read-only mode (false)
0119      */
0120     void setReadWrite(bool newReadWrite);
0121     /**
0122      * Fired when the read/write property changes
0123      */
0124     Q_SIGNAL void readWriteChanged();
0125 
0126     /**
0127      * @return whether the book has been modified and has unsaved changes.
0128      * 
0129      * Used in PeruseCreator to determine whether to enable the save dialog.
0130      */
0131     bool hasUnsavedChanges() const;
0132     /**
0133      * \brief Set that the book has been modified.
0134      * @param isDirty whether the book has been modified.
0135      */
0136     Q_INVOKABLE void setDirty(bool isDirty = true);
0137     /**
0138      * \brief Fires when there are unsaved changes.
0139      */
0140     Q_SIGNAL void hasUnsavedChangesChanged();
0141 
0142     /**
0143      * A list of every file contained within the archive, not just the pages
0144      * @return A list of files relative to the archive root
0145      */
0146     QStringList fileEntries() const;
0147     /**
0148      * Fired when the contents of the archive change
0149      */
0150     Q_SIGNAL void fileEntriesChanged();
0151 
0152     /**
0153      * \brief Whether or not a specific file entry is referenced somewhere in the ACBF document.
0154      * @param fileEntry The archive filename for the entry you want checked
0155      * @return Whether the file is referenced or not. 0 if not, 1 if fully matched, 2 if partially matched
0156      * @see fileEntries()
0157      * @see markArchiveFileForDeletion(QString,bool)
0158      */
0159     Q_INVOKABLE int fileEntryReferenced(const QString& fileEntry) const;
0160 
0161     /**
0162      * \brief Whether or not an entry is a directory in the archive (as opposed to a file)
0163      * This becomes useful for distinguishing what should be done for things that are not actually
0164      * files (and consequently not really directly useful in a book, as you can't simply link to
0165      * a directory in the archive)
0166      * @param fileEntry The entry you wish to check
0167      * @return True if the entry passed in is a directory
0168      */
0169     Q_INVOKABLE bool fileEntryIsDirectory(const QString& fileEntry) const;
0170 
0171     /**
0172      * @brief The list of files currently marked for deletion
0173      * @return A list of files marked for deletion on the next save action
0174      */
0175     QStringList fileEntriesToDelete() const;
0176     /**
0177      * Fired whenever the list of file entries which should be deleted changes
0178      */
0179     Q_SIGNAL void fileEntriesToDeleteChanged();
0180     /**
0181      * \brief Mark a file for removal from the archive
0182      * When saving the book, files marked for deletion will not be included in the new archive.
0183      *
0184      * @param archiveFile The filename of the file to be removed
0185      * @param markForDeletion Whether the archive file should be deleted or not
0186      */
0187     Q_INVOKABLE void markArchiveFileForDeletion(const QString& archiveFile, bool markForDeletion = true);
0188 
0189     /**
0190      * \brief Saves the archive back to disk
0191      * @return True if the save was successful
0192      */
0193     Q_INVOKABLE bool saveBook();
0194 
0195     /**
0196      * \brief add a page to this book.
0197      * 
0198      * This adds it to the ACBF metadata too.
0199      * 
0200      * @param url The resource location of the page as an url.
0201      * @param title The title of the page. This is shown in a table of contents.
0202      */
0203     void addPage(QString url, QString title) override;
0204 
0205     /**
0206      * @brief removePage
0207      * remove the given page from the book by number.
0208      * @note This does not remove the file pointed to by the page
0209      * @see markArchiveFileForDeletion(QString,bool)
0210      * @param pageNumber the number of the page to remove.
0211      */
0212     Q_INVOKABLE void removePage(int pageNumber) override;
0213 
0214     /**
0215      * Adds a new page to the book archive on disk, by copying in the file
0216      * passed to the function. Optionally this can be done at a specific
0217      * position in the book.
0218      *
0219      * @param fileUrl     The URL of the file to copy into the archive
0220      * @param insertAfter The index to insert the new page after. If invalid, insertion will be at the end
0221      */
0222     Q_INVOKABLE void addPageFromFile(QString fileUrl, int insertAfter = -1);
0223 
0224     /**
0225      * @brief Swap the two pages at the specified indices
0226      *
0227      * This will change the order in the archive file as well (that is, renaming the files inside the archive)
0228      *
0229      * @param swapThisIndex The index of the first page to be swapped
0230      * @param withThisIndex The index of the page you want the first to be swapped with
0231      */
0232     Q_INVOKABLE void swapPages(int swapThisIndex, int withThisIndex) override;
0233 
0234     /**
0235      * Creates a new book in the folder, with the given title and cover.
0236      * A filename will be constructed to fit the title, and which does not already exist in the
0237      * directory.
0238      * 
0239      * @param folder the path to the folder to create this book in.
0240      * @param title The title of the book.
0241      * @param coverUrl A resource location pointing at the image that will be the coverpage.
0242      */
0243     Q_INVOKABLE QString createBook(QString folder, QString title, QString coverUrl);
0244 
0245     /**
0246      * Get the preview URL for an acbf item with the given ID.
0247      * @note If you are requesting a preview for an entry in the ACBF data, prepend the ID with a # symbol
0248      * @param id The ID of the item to get a preview URL for
0249      * @return The preview URL for the item with the given ID (this is NOT checked for validity, only constructed)
0250      */
0251     Q_INVOKABLE QString previewForId(const QString& id) const;
0252 
0253     /**
0254      * Get the family name for a font by its filename as stored in the ACBF data, or in the archive.
0255      * The font will be loaded on the first call of this function, and removed when the model
0256      * is destructed.
0257      * @param fontFileName The filename, in the acbf document or archive, of the font you wish to load
0258      * @return The first family name in the font, or an empty string if none was found
0259      */
0260     Q_INVOKABLE QString fontFamilyName(const QString& fontFileName);
0261 
0262     /**
0263      * Goes through a list of font families (such as that in a stylesheet) and returns the first one
0264      * available in the system. This function will also attempt to load any fonts that are in the
0265      * acbf data, or in the archive (using the fontFamilyName(QString) function)
0266      * @param fontList The ordered list of fonts to attempt to locate, in a fail-through fashion
0267      * @param The first font in the list that's available on the system. If none is found, an empty string is returned.
0268      */
0269     Q_INVOKABLE QString firstAvailableFont(const QStringList& fontList);
0270 
0271     friend class ArchiveImageRunnable;
0272 protected:
0273     const KArchiveFile* archiveFile(const QString& filePath) const;
0274     QMutex archiveMutex;
0275 
0276 private:
0277     class Private;
0278     /**
0279      * @brief loadComicInfoXML
0280      * Loads ComicInfo.xml, this is an old file metadata type used by comicrack, and since then
0281      * written by other editors, amongst which a callibre plugin.
0282      * @param xmlDocument string with the archive value.
0283      * @param acbfData a pointer pointing to a acbfDocument.
0284      * @param entries a list of image entries, sorted.
0285      * @param filename the file name of the document, necessary for writing data to kfilemetadata.
0286      * @return whether the reading was successful.
0287      */
0288     bool loadComicInfoXML(QString xmlDocument, QObject* acbfData, QStringList entries, QString filename);
0289     /**
0290      * @brief loads CoMet xmls, https://www.denvog.com/comet/comet-specification/
0291      * @param xmlDocument string with the archive value.
0292      * @param acbfData a pointer pointing to a acbfDocument.
0293      * @param entries a list of image entries, sorted.
0294      * @param filename the file name of the document, necessary for writing data to kfilemetadata.
0295      * @return whether the reading was successful.
0296      */
0297     bool loadCoMet(QStringList xmlDocuments, QObject* acbfData, QStringList entries, QString filename);
0298     Private* d;
0299 };
0300 
0301 #endif//ARCHIVEBOOKMODEL_H