1 
2 /*
3    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4    All rights reserved.
5 
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9 
10    1. Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 
29 #ifndef KP_DOCUMENT_H
30 #define KP_DOCUMENT_H
31 
32 
33 #include <QBitmap>
34 #include <QObject>
35 #include <QString>
36 #include <QUrl>
37 
38 #include "imagelib/kpImage.h"
39 #include "pixmapfx/kpPixmapFX.h"
40 #undef environ
41 
42 class QImage;
43 class QIODevice;
44 class QPoint;
45 class QRect;
46 class QSize;
47 
48 class kpColor;
49 class kpDocumentEnvironment;
50 class kpDocumentSaveOptions;
51 class kpDocumentMetaInfo;
52 class kpAbstractImageSelection;
53 class kpAbstractSelection;
54 class kpTextSelection;
55 
56 
57 // REFACTOR: rearrange method order to make sense and reflect kpDocument_*.cpp split.
58 class kpDocument : public QObject
59 {
60 Q_OBJECT
61 
62 public:
63     // REFACTOR: Hide constructor and have 2 factory methods:
64     //
65     //           Method 1. Creates a blank document with dimensions <w>x<h>.
66     //
67     //           Method 2. Calls open().  <w> and <h> (aka constructorWidth()
68     //              and constructorHeight()) need not be specified.
69     //
70     //           ?
71     kpDocument (int w, int h, kpDocumentEnvironment *environ);
72     ~kpDocument () override;
73 
74     kpDocumentEnvironment *environ () const;
75     void setEnviron (kpDocumentEnvironment *environ);
76 
77 
78     //
79     // File I/O - Open
80     //
81 
82 
83     static QImage getPixmapFromFile (const QUrl &url, bool suppressDoesntExistDialog,
84                                      QWidget *parent,
85                                      kpDocumentSaveOptions *saveOptions = nullptr,
86                                      kpDocumentMetaInfo *metaInfo = nullptr);
87     // REFACTOR: fix: open*() should only be called once.
88     //                Create a new kpDocument() if you want to open again.
89     void openNew (const QUrl &url);
90     bool open (const QUrl &url, bool newDocSameNameIfNotExist = false);
91 
92     static void getDataFromImage(const QImage &image,
93                                  kpDocumentSaveOptions &saveOptions,
94                                  kpDocumentMetaInfo &metaInfo);
95 
96     //
97     // File I/O - Save
98     //
99 
100     static bool lossyPromptContinue (const QImage &pixmap,
101                                      const kpDocumentSaveOptions &saveOptions,
102                                      QWidget *parent);
103     static bool savePixmapToDevice (const QImage &pixmap,
104                                     QIODevice *device,
105                                     const kpDocumentSaveOptions &saveOptions,
106                                     const kpDocumentMetaInfo &metaInfo,
107                                     bool lossyPrompt,
108                                     QWidget *parent,
109                                     bool *userCancelled = nullptr);
110     static bool savePixmapToFile (const QImage &pixmap,
111                                   const QUrl &url,
112                                   const kpDocumentSaveOptions &saveOptions,
113                                   const kpDocumentMetaInfo &metaInfo,
114                                   bool lossyPrompt,
115                                   QWidget *parent);
116     bool save (bool lossyPrompt = false);
117     bool saveAs (const QUrl &url,
118                  const kpDocumentSaveOptions &saveOptions,
119                  bool lossyPrompt = true);
120 
121 
122     // Returns whether save() or saveAs() have ever been called and returned true
123     bool savedAtLeastOnceBefore () const;
124 
125     QUrl url () const;
126     void setURL (const QUrl &url, bool isFromExistingURL);
127 
128     // Returns whether the document's image was successfully opened from
129     // or saved to the URL returned by url().  This is not true for a
130     // new kpDocument and in the case of open() being passed
131     // "newDocSameNameIfNotExist = true" when the URL doesn't exist.
132     //
133     // If this returns true and the kpDocument hasn't been modified,
134     // this gives a pretty good indication that the image stored at url()
135     // is equal to image() (unless the something has happened to that url
136     // outside of KolourPaint).
137     //
138     // e.g. If the user types "kolourpaint doesnotexist.png" to start
139     //      KolourPaint, this method will return false.
140     bool isFromExistingURL () const;
141 
142     // Checks whether @p url still exists
143     bool urlExists (const QUrl &url) const;
144 
145     // (will convert: empty Url --> "Untitled")
146     QString prettyUrl () const;
147 
148     // (will convert: empty Url --> "Untitled")
149     QString prettyFilename () const;
150 
151     // (guaranteed to return valid pointer)
152 
153     const kpDocumentSaveOptions *saveOptions () const;
154     void setSaveOptions (const kpDocumentSaveOptions &saveOptions);
155 
156     const kpDocumentMetaInfo *metaInfo () const;
157     void setMetaInfo (const kpDocumentMetaInfo &metaInfo);
158 
159 
160     /*
161      * Properties (modified, width, height, color depth...)
162      */
163 
164     void setModified (bool yes = true);
165     bool isModified () const;
166     bool isEmpty () const;
167 
168     // REFACTOR: Rename to originalWidth()?
169     int constructorWidth () const;  // as passed to the constructor
170     int width (bool ofSelection = false) const;
171     int oldWidth () const;  // only valid in a slot connected to sizeChanged()
172     void setWidth (int w, const kpColor &backgroundColor);
173 
174     // REFACTOR: Rename to originalHeight()?
175     int constructorHeight () const;  // as passed to the constructor
176     int height (bool ofSelection = false) const;
177     int oldHeight () const;  // only valid in a slot connected to sizeChanged()
178     void setHeight (int h, const kpColor &backgroundColor);
179 
180     QRect rect (bool ofSelection = false) const;
181 
182 
183     //
184     // Image access
185     //
186 
187     // Returns a copy of part of the document's image (not including the
188     // selection).
189     kpImage getImageAt (const QRect &rect) const;
190 
191     void setImageAt (const kpImage &image, const QPoint &at);
192 
193     // "image(false)" returns a copy of the document's image, ignoring any
194     // floating selection.
195     //
196     // "image(true)" returns a copy of a floating image selection's base
197     // image (i.e. before selection transparency is applied), which may be
198     // null if the image selection is a just a border.
199     //
200     // ASSUMPTION: For <ofSelection> == true only, an image selection exists.
201     kpImage image (bool ofSelection = false) const;
202     kpImage *imagePointer () const;
203 
204     void setImage (const kpImage &image);
205     // ASSUMPTION: If setting the selection's image, the selection must be
206     //             an image selection.
207     void setImage (bool ofSelection, const kpImage &image);
208 
209 
210     //
211     // Selections
212     //
213 
214 public:
215     kpAbstractSelection *selection () const;
216     kpAbstractImageSelection *imageSelection () const;
217     kpTextSelection *textSelection () const;
218 
219     // Sets the document's selection to the given one and changes to the
220     // matching selection tool.  Tool changes occur in the following situations:
221     //
222     // 1. Setting a <selection> when a selection tool is not active.
223     //
224     // 2. Setting an image <selection> when the text tool is active.
225     //    ASSUMPTION: There is no text selection active when calling this
226     //                method (push it onto the document before calling this,
227     //                to avoid this problem).
228     //
229     // 3. Setting a text <selection> when an image selection tool is active.
230     //    ASSUMPTION: There is no image selection active when calling this
231     //                method (push it onto the document before calling this,
232     //                to avoid this problem).
233     //
234     // The justification for the above assumptions are to reduce the complexity
235     // of this method's implementation -- changing from an image selection tool
236     // to a text selection tool, or vice-versa, calls the end() method of the
237     // current tool, which pushes any active selection onto the document.  Since
238     // this method sets the selection, losing the old selection in the middle of
239     // the method would be tricky to work around.
240     //
241     // WARNING: Before calling this, you must ensure that the UI (kpMainWindow)
242     //          has the <selection>'s selection transparency or
243     //          for a text selection, its text style, selected.
244     // TODO: Why can't we change it for them, if we change tool automatically for them already?
245     void setSelection (const kpAbstractSelection &selection);
246 
247     // Returns the base image of the current image selection.  If this is
248     // null (because the selection is still a border), it extracts the
249     // pixels of the document marked out by the border of the selection.
250     //
251     // ASSUMPTION: There is an imageSelection().
252     //
253     // TODO: this always returns base image - need ver that applies selection
254     //       transparency.
255     kpImage getSelectedBaseImage () const;
256 
257     // Sets the base image of the current image selection to the pixels
258     // of the document marked out by the border of the selection.
259     //
260     // ASSUMPTION: There is an imageSelection() that is just a border
261     //             (no base image).
262     void imageSelectionPullFromDocument (const kpColor &backgroundColor);
263 
264     // Deletes the current selection, if there is a selection(), else NOP
265     void selectionDelete ();
266 
267     // Stamps a copy of the selection onto the document.
268     //
269     // For image selections, <applySelTransparency> set to true, means that
270     // the transparent image of the selection is used.  If set to false,
271     // the base image of the selection is used.  This argument is ignored
272     // for non-image selections.
273     //
274     // ASSUMPTION: There is a selection() with content, else NOP
275     void selectionCopyOntoDocument (bool applySelTransparency = true);
276 
277     // Same as selectionCopyOntoDocument() but deletes the selection
278     // afterwards.
279     void selectionPushOntoDocument (bool applySelTransparency = true);
280 
281     //
282     // Same as image() but returns a _copy_ of the document image
283     // + any (even non-image) selection pasted on top.
284     //
285     // Even if the selection has no content, it is still pasted:
286     //
287     // 1. For an image selection, this makes no difference.
288     //
289     // 2. For a text selection:
290     //
291     //    a) with an opaque background: the background rectangle is
292     //      included -- this is necessary since the rectangle is visually
293     //      there after all, and the intention of this method is to report
294     //      everything.
295     //
296     //    b) with a transparent background: this makes no difference.
297     //
298     kpImage imageWithSelection () const;
299 
300 
301     /*
302      * Transformations
303      * (convenience only - you could achieve the same effect (and more) with
304      *  kpPixmapFX: these functions do not affect the selection)
305      */
306 
307     void fill (const kpColor &color);
308     void resize (int w, int h, const kpColor &backgroundColor);
309 
310 
311 public slots:
312     // these will emit signals!
313     void slotContentsChanged (const QRect &rect);
314     void slotSizeChanged (const QSize &newSize);
315 
316 signals:
317     void documentOpened ();
318     void documentSaved ();
319 
320     // Emitted whenever the isModified() flag changes from false to true.
321     // This is the _only_ signal that may be emitted in addition to the others.
322     void documentModified ();
323 
324     void contentsChanged (const QRect &rect);
325     void sizeChanged (int newWidth, int newHeight);  // see oldWidth(), oldHeight()
326     void sizeChanged (const QSize &newSize);
327 
328     void selectionEnabled (bool on);
329 
330     // Emitted when setSelection() is given a selection such that we change
331     // from a non-text-selection tool to the text selection tool or vice-versa.
332     // <isText> reports whether the new selection is text (and therefore,
333     // whether we've switched to the text tool).
334     void selectionIsTextChanged (bool isText);
335 
336 private:
337     int m_constructorWidth, m_constructorHeight;
338     kpImage *m_image;
339 
340     QUrl m_url;
341     bool m_isFromExistingURL;
342     bool m_savedAtLeastOnceBefore;
343 
344     kpDocumentSaveOptions *m_saveOptions;
345     kpDocumentMetaInfo *m_metaInfo;
346 
347     bool m_modified;
348 
349     kpAbstractSelection *m_selection;
350 
351     int m_oldWidth, m_oldHeight;
352 
353     // There is no need to maintain binary compatibility at this stage.
354     // The d-pointer is just so that you can experiment without recompiling
355     // the kitchen sink.
356     struct kpDocumentPrivate *d;
357 };
358 
359 
360 #endif  // KP_DOCUMENT_H
361