1 /*
2  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) version 3, or any
8  * later version accepted by the membership of KDE e.V. (or its
9  * successor approved by the membership of KDE e.V.), which shall
10  * act as a proxy defined in Section 6 of version 3 of the license.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef ACBFPAGE_H
23 #define ACBFPAGE_H
24 
25 #include "AcbfDocument.h"
26 /**
27  * \brief Class to handle page objects.
28  *
29  * A proper ACBF document should have entries for all pages
30  * and said entries should point at the images that make up
31  * the comic.
32  *
33  * However, ACBF also has room from frame definitions, transcriptions,
34  * translations, table of contents, jumps and more.
35  *
36  * The frame definitions are used to navigate a page and zoom efficiently on a
37  * small screen. Similarly, transscriptions and translations can be used to show
38  * text when the image itself is too blurry.
39  *
40  * Title is used to generate a table of contents.
41  *
42  * Transition is to indicate extra information about how the page should be entered.
43  *
44  * bgcolor is used by the reading software to determine what background color to give.
45  *
46  * Jumps can be used to move around in the comic.
47  *
48  * TODO: Frame and Jump seem to be missing classes despite being used here?
49  */
50 class QXmlStreamWriter;
51 class QXmlStreamReader;
52 namespace AdvancedComicBookFormat
53 {
54 class Textlayer;
55 class Frame;
56 class Jump;
57 class ACBF_EXPORT Page : public QObject
58 {
59     Q_OBJECT
60     Q_PROPERTY(QString bgcolor READ bgcolor WRITE setBgcolor NOTIFY bgcolorChanged)
61     Q_PROPERTY(QString transition READ transition WRITE setTransition NOTIFY transitionChanged)
62     Q_PROPERTY(QString imageHref READ imageHref WRITE setImageHref NOTIFY imageHrefChanged)
63     Q_PROPERTY(QStringList textLayerLanguages READ textLayerLanguages NOTIFY textLayerLanguagesChanged)
64     Q_PROPERTY(QStringList framePointStrings READ framePointStrings NOTIFY framePointStringsChanged)
65     Q_PROPERTY(QObjectList jumps READ jumps NOTIFY jumpsChanged)
66 public:
67     // Pages can also be cover pages, which means they can also be children of BookInfo
68     explicit Page(Document* parent = nullptr);
69     ~Page() override;
70 
71     /**
72      * \brief Write the page into the xml writer.
73      */
74     void toXml(QXmlStreamWriter* writer);
75     /**
76      * \brief load a page element into this object.
77      * @return True if the xmlReader encountered no errors.
78      */
79     bool fromXml(QXmlStreamReader *xmlReader);
80 
81     /**
82      * @return the background color as a QString.
83      *
84      * It should be an 8bit per channel rgb hexcode.
85      */
86     QString bgcolor() const;
87     /**
88      * \brief set the background color.
89      *
90      * @param newColor - a String with an 8bit per channel rgb hexcode (#ff00ff, or the like)
91      */
92     void setBgcolor(const QString& newColor = QString());
93     /**
94      * @brief fires when the background color changes.
95      */
96     Q_SIGNAL void bgcolorChanged();
97     /**
98      * @return transition type as a string.
99      */
100     QString transition() const;
101     /**
102      * \brief set the transition type.
103      * @param transition - the transition type, possible entries are in the availableTransitions() stringlist.
104      */
105     void setTransition(const QString& transition);
106     /**
107      * @brief fires when the transition type changes.
108      */
109     Q_SIGNAL void transitionChanged();
110     /**
111      * @returns a list of strings that can be used for the transition.
112      */
113     Q_INVOKABLE static QStringList availableTransitions();
114 
115     /**
116      * @return all titles for this page in all languages.
117      */
118     Q_INVOKABLE QStringList titleForAllLanguages() const;
119     /**
120      * @param language - the language of the entry in language code, country
121      * code format joined by a dash (not an underscore).
122      * @return the title for this language.
123      */
124     Q_INVOKABLE QString title(const QString& language = QString()) const;
125     /**
126      * \brief set the title for this language.
127      * @param language - the language of the entry in language code, country
128      * code format joined by a dash (not an underscore).
129      */
130     Q_INVOKABLE void setTitle(const QString& title, const QString& language = QString());
131     /**
132      * @brief titlesChanged
133      */
134     Q_SIGNAL void titlesChanged();
135 
136     /**
137      * @returns the URI for the image of this page as a QString
138      */
139     QString imageHref() const;
140     /**
141      * \brief set the URI for the image of this page.
142      * @param imageHref - the URI to an image.
143      *
144      *  - A Binary representation will use the ID of that representation.
145      *  - A reference to a file on the internet will start with "http://" or "https://"
146      *  - A reference to a file in a zip will be prefixed with "zip:"
147      *  - Everything else is presumed to be a file on disk.
148      */
149     void setImageHref(const QString& imageHref);
150     /**
151      * @brief fires when the image url changes.
152      */
153     Q_SIGNAL void imageHrefChanged();
154 
155     /**
156      * @returns all the textlayers objects.
157      */
158     QList<Textlayer*> textLayersForAllLanguages() const;
159     /**
160      * @param language - the language of the entry in language code, country
161      * code format joined by a dash (not an underscore).
162      * @returns the TextLayer object for that language.
163      */
164     Q_INVOKABLE Textlayer* textLayer(const QString& language = QString()) const;
165     /**
166      *
167      * @param language - the language of the entry in language code, country
168      * code format joined by a dash (not an underscore). Setting the textlayer
169      * for a language to null removes that language (as with other translated
170      * entries, though this one not being text warranted a comment)
171      */
172     void setTextLayer(Textlayer* textlayer, const QString& language = QString());
173     /**
174      * @brief add a textlayer for language.
175      * @param language code to add a textlayer for.
176      */
177     Q_INVOKABLE void addTextLayer(const QString& language = QString());
178     /**
179      * @brief remove a text layer by language.
180      * @param language code to remove the textlayer for.
181      */
182     Q_INVOKABLE void removeTextLayer(const QString& language = QString());
183     /**
184      * @brief duplicate a text layer to a different language, if languageFrom doesn't
185      * exist this makes a new text layer.
186      * @param languageFrom the language from which to duplicate.
187      * @param languageTo the language to make the new text layer at.
188      */
189     Q_INVOKABLE void duplicateTextLayer(const QString&languageFrom, const QString& languageTo = QString());
190     /**
191      * @brief get the possible translations.
192      * @return a stringlist with all the languages available.
193      */
194     QStringList textLayerLanguages() const;
195     /**
196      * @brief fires when the textlayer languages list changes
197      *
198      * this can happen when text layers are added or removed.
199      */
200     Q_SIGNAL void textLayerLanguagesChanged();
201 
202     /**
203      * @returns a list of frames in this page.
204      */
205     QList<Frame*> frames() const;
206     /**
207      * @param index - index of the frame.
208      * @return the frame of that index.
209      */
210     Q_INVOKABLE Frame* frame(int index) const;
211     /**
212      * @param frame - the frame you want to index of.
213      * @returns the index of the given frame.
214      */
215     int frameIndex(Frame* frame) const;
216 
217     /**
218      * \brief add a frame to the list of frames.
219      * @param frame - the frame to add.
220      * @param index - the index to add it at. If afterIndex is larger than
221      * zero, the insertion will happen at that index
222      */
223     void addFrame(Frame* frame, int index = -1);
224     /**
225      * \brief remove the given frame from the framelist.
226      * @param frame - the frame to remove.
227      */
228     void removeFrame(Frame* frame);
229     /**
230      * @brief remove frame by index.
231      * @param index index of the frame to remove.
232      */
233     Q_INVOKABLE void removeFrame(int index);
234     /**
235      * @brief add a frame at index..
236      * @param index - the index to add it at. If afterIndex is larger than
237      * zero, the insertion will happen at that index
238      */
239     Q_INVOKABLE void addFrame(int index = -1);
240     /**
241      * \brief Swap two frames in the list.
242      * @param swapThis - the first index to swap.
243      * @param withThis - the second index to swap.
244      */
245     Q_INVOKABLE bool swapFrames(int swapThis, int withThis);
246     /**
247      * @brief returns the amount of frames as a stringlist.
248      * This is a hack to ensure that qml repeaters may update properly.
249      * @return a string list containing strings with the point counts of said frames.
250      */
251     QStringList framePointStrings();
252     /**
253      * @brief fires when the frame point strings change.
254      */
255     Q_SIGNAL void framePointStringsChanged();
256 
257     /**
258      * @return the list of jump objects for this page.
259      */
260     QObjectList jumps() const;
261     /**
262      * @param index - the index for which you want the jump object.
263      * @return a jump object for the given frame.
264      */
265     Q_INVOKABLE Jump* jump(int index) const;
266     /**
267      * @param jump - the jump you want to index of.
268      * @returns the index of the given jump.
269      */
270     int jumpIndex(Jump* jump) const;
271 
272     /**
273      * \brief add a jump to the list of frames.
274      * @param jump - the jump to add.
275      * @param index - the index to add it at. If afterIndex is larger than
276      * zero, the insertion will happen at that index
277      */
278     void addJump(Jump* jump, int index = -1);
279     /**
280      * @brief addJump
281      * @param index - the index to add it at. If afterIndex is larger than
282      * zero, the insertion will happen at that index
283      */
284     Q_INVOKABLE void addJump(int pageIndex, int index = -1);
285     /**
286      * \brief remove the given jump from the list of jumps.
287      * @param jump - the jump to remove.
288      */
289     void removeJump(Jump* jump);
290     /**
291      * @brief removeJump
292      * @param index to remove the jump at.
293      */
294     Q_INVOKABLE void removeJump(int index);
295     /**
296      * \brief Swap two jumps in the list.
297      * @param swapThis - the first index to swap.
298      * @param withThis - the second index to swap.
299      */
300     Q_INVOKABLE bool swapJumps(int swapThis, int withThis);
301     /**
302      * @brief Emitted when the list of jumps changes.
303      */
304     Q_SIGNAL void jumpsChanged();
305 
306     /**
307      * @returns whether this is the cover page.
308      */
309     bool isCoverPage() const;
310     /**
311      * \brief toggle whether this is the cover page.
312      *
313      */
314     void setIsCoverPage(bool isCoverPage = false);
315 private:
316     class Private;
317     std::unique_ptr<Private> d;
318 };
319 }
320 
321 #endif//ACBFPAGE_H
322