File indexing completed on 2024-04-28 04:20:13

0001 
0002 /*
0003    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0004    All rights reserved.
0005 
0006    Redistribution and use in source and binary forms, with or without
0007    modification, are permitted provided that the following conditions
0008    are met:
0009 
0010    1. Redistributions of source code must retain the above copyright
0011       notice, this list of conditions and the following disclaimer.
0012    2. Redistributions in binary form must reproduce the above copyright
0013       notice, this list of conditions and the following disclaimer in the
0014       documentation and/or other materials provided with the distribution.
0015 
0016    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026 */
0027 
0028 
0029 #ifndef KP_DOCUMENT_H
0030 #define KP_DOCUMENT_H
0031 
0032 
0033 #include <QObject>
0034 #include <QString>
0035 #include <QUrl>
0036 
0037 #include "imagelib/kpImage.h"
0038 #include "pixmapfx/kpPixmapFX.h"
0039 #undef environ
0040 
0041 class QImage;
0042 class QIODevice;
0043 class QPoint;
0044 class QRect;
0045 class QSize;
0046 
0047 class kpColor;
0048 class kpDocumentEnvironment;
0049 class kpDocumentSaveOptions;
0050 class kpDocumentMetaInfo;
0051 class kpAbstractImageSelection;
0052 class kpAbstractSelection;
0053 class kpTextSelection;
0054 
0055 
0056 // REFACTOR: rearrange method order to make sense and reflect kpDocument_*.cpp split.
0057 class kpDocument : public QObject
0058 {
0059 Q_OBJECT
0060 
0061 public:
0062     // REFACTOR: Hide constructor and have 2 factory methods:
0063     //
0064     //           Method 1. Creates a blank document with dimensions <w>x<h>.
0065     //
0066     //           Method 2. Calls open().  <w> and <h> (aka constructorWidth()
0067     //              and constructorHeight()) need not be specified.
0068     //
0069     //           ?
0070     kpDocument (int w, int h, kpDocumentEnvironment *environ);
0071     ~kpDocument () override;
0072 
0073     kpDocumentEnvironment *environ () const;
0074     void setEnviron (kpDocumentEnvironment *environ);
0075 
0076 
0077     //
0078     // File I/O - Open
0079     //
0080 
0081 
0082     static QImage getPixmapFromFile (const QUrl &url, bool suppressDoesntExistDialog,
0083                                      QWidget *parent,
0084                                      kpDocumentSaveOptions *saveOptions = nullptr,
0085                                      kpDocumentMetaInfo *metaInfo = nullptr);
0086     // REFACTOR: fix: open*() should only be called once.
0087     //                Create a new kpDocument() if you want to open again.
0088     void openNew (const QUrl &url);
0089     bool open (const QUrl &url, bool newDocSameNameIfNotExist = false);
0090 
0091     static void getDataFromImage(const QImage &image,
0092                                  kpDocumentSaveOptions &saveOptions,
0093                                  kpDocumentMetaInfo &metaInfo);
0094 
0095     //
0096     // File I/O - Save
0097     //
0098 
0099     static bool lossyPromptContinue (const QImage &pixmap,
0100                                      const kpDocumentSaveOptions &saveOptions,
0101                                      QWidget *parent);
0102     static bool savePixmapToDevice (const QImage &pixmap,
0103                                     QIODevice *device,
0104                                     const kpDocumentSaveOptions &saveOptions,
0105                                     const kpDocumentMetaInfo &metaInfo,
0106                                     bool lossyPrompt,
0107                                     QWidget *parent,
0108                                     bool *userCancelled = nullptr);
0109     static bool savePixmapToFile (const QImage &pixmap,
0110                                   const QUrl &url,
0111                                   const kpDocumentSaveOptions &saveOptions,
0112                                   const kpDocumentMetaInfo &metaInfo,
0113                                   bool lossyPrompt,
0114                                   QWidget *parent);
0115     bool save (bool lossyPrompt = false);
0116     bool saveAs (const QUrl &url,
0117                  const kpDocumentSaveOptions &saveOptions,
0118                  bool lossyPrompt = true);
0119 
0120 
0121     // Returns whether save() or saveAs() have ever been called and returned true
0122     bool savedAtLeastOnceBefore () const;
0123 
0124     QUrl url () const;
0125     void setURL (const QUrl &url, bool isFromExistingURL);
0126 
0127     // Returns whether the document's image was successfully opened from
0128     // or saved to the URL returned by url().  This is not true for a
0129     // new kpDocument and in the case of open() being passed
0130     // "newDocSameNameIfNotExist = true" when the URL doesn't exist.
0131     //
0132     // If this returns true and the kpDocument hasn't been modified,
0133     // this gives a pretty good indication that the image stored at url()
0134     // is equal to image() (unless the something has happened to that url
0135     // outside of KolourPaint).
0136     //
0137     // e.g. If the user types "kolourpaint doesnotexist.png" to start
0138     //      KolourPaint, this method will return false.
0139     bool isFromExistingURL () const;
0140 
0141     // Checks whether @p url still exists
0142     bool urlExists (const QUrl &url) const;
0143 
0144     // (will convert: empty Url --> "Untitled")
0145     QString prettyUrl () const;
0146 
0147     // (will convert: empty Url --> "Untitled")
0148     QString prettyFilename () const;
0149 
0150     // (guaranteed to return valid pointer)
0151 
0152     const kpDocumentSaveOptions *saveOptions () const;
0153     void setSaveOptions (const kpDocumentSaveOptions &saveOptions);
0154 
0155     const kpDocumentMetaInfo *metaInfo () const;
0156     void setMetaInfo (const kpDocumentMetaInfo &metaInfo);
0157 
0158 
0159     /*
0160      * Properties (modified, width, height, color depth...)
0161      */
0162 
0163     void setModified (bool yes = true);
0164     bool isModified () const;
0165     bool isEmpty () const;
0166 
0167     // REFACTOR: Rename to originalWidth()?
0168     int constructorWidth () const;  // as passed to the constructor
0169     int width (bool ofSelection = false) const;
0170     int oldWidth () const;  // only valid in a slot connected to sizeChanged()
0171     void setWidth (int w, const kpColor &backgroundColor);
0172 
0173     // REFACTOR: Rename to originalHeight()?
0174     int constructorHeight () const;  // as passed to the constructor
0175     int height (bool ofSelection = false) const;
0176     int oldHeight () const;  // only valid in a slot connected to sizeChanged()
0177     void setHeight (int h, const kpColor &backgroundColor);
0178 
0179     QRect rect (bool ofSelection = false) const;
0180 
0181 
0182     //
0183     // Image access
0184     //
0185 
0186     // Returns a copy of part of the document's image (not including the
0187     // selection).
0188     kpImage getImageAt (const QRect &rect) const;
0189 
0190     void setImageAt (const kpImage &image, const QPoint &at);
0191 
0192     // "image(false)" returns a copy of the document's image, ignoring any
0193     // floating selection.
0194     //
0195     // "image(true)" returns a copy of a floating image selection's base
0196     // image (i.e. before selection transparency is applied), which may be
0197     // null if the image selection is a just a border.
0198     //
0199     // ASSUMPTION: For <ofSelection> == true only, an image selection exists.
0200     kpImage image (bool ofSelection = false) const;
0201     kpImage *imagePointer () const;
0202 
0203     void setImage (const kpImage &image);
0204     // ASSUMPTION: If setting the selection's image, the selection must be
0205     //             an image selection.
0206     void setImage (bool ofSelection, const kpImage &image);
0207 
0208 
0209     //
0210     // Selections
0211     //
0212 
0213 public:
0214     kpAbstractSelection *selection () const;
0215     kpAbstractImageSelection *imageSelection () const;
0216     kpTextSelection *textSelection () const;
0217 
0218     // Sets the document's selection to the given one and changes to the
0219     // matching selection tool.  Tool changes occur in the following situations:
0220     //
0221     // 1. Setting a <selection> when a selection tool is not active.
0222     //
0223     // 2. Setting an image <selection> when the text tool is active.
0224     //    ASSUMPTION: There is no text selection active when calling this
0225     //                method (push it onto the document before calling this,
0226     //                to avoid this problem).
0227     //
0228     // 3. Setting a text <selection> when an image selection tool is active.
0229     //    ASSUMPTION: There is no image selection active when calling this
0230     //                method (push it onto the document before calling this,
0231     //                to avoid this problem).
0232     //
0233     // The justification for the above assumptions are to reduce the complexity
0234     // of this method's implementation -- changing from an image selection tool
0235     // to a text selection tool, or vice-versa, calls the end() method of the
0236     // current tool, which pushes any active selection onto the document.  Since
0237     // this method sets the selection, losing the old selection in the middle of
0238     // the method would be tricky to work around.
0239     //
0240     // WARNING: Before calling this, you must ensure that the UI (kpMainWindow)
0241     //          has the <selection>'s selection transparency or
0242     //          for a text selection, its text style, selected.
0243     // TODO: Why can't we change it for them, if we change tool automatically for them already?
0244     void setSelection (const kpAbstractSelection &selection);
0245 
0246     // Returns the base image of the current image selection.  If this is
0247     // null (because the selection is still a border), it extracts the
0248     // pixels of the document marked out by the border of the selection.
0249     //
0250     // ASSUMPTION: There is an imageSelection().
0251     //
0252     // TODO: this always returns base image - need ver that applies selection
0253     //       transparency.
0254     kpImage getSelectedBaseImage () const;
0255 
0256     // Sets the base image of the current image selection to the pixels
0257     // of the document marked out by the border of the selection.
0258     //
0259     // ASSUMPTION: There is an imageSelection() that is just a border
0260     //             (no base image).
0261     void imageSelectionPullFromDocument (const kpColor &backgroundColor);
0262 
0263     // Deletes the current selection, if there is a selection(), else NOP
0264     void selectionDelete ();
0265 
0266     // Stamps a copy of the selection onto the document.
0267     //
0268     // For image selections, <applySelTransparency> set to true, means that
0269     // the transparent image of the selection is used.  If set to false,
0270     // the base image of the selection is used.  This argument is ignored
0271     // for non-image selections.
0272     //
0273     // ASSUMPTION: There is a selection() with content, else NOP
0274     void selectionCopyOntoDocument (bool applySelTransparency = true);
0275 
0276     // Same as selectionCopyOntoDocument() but deletes the selection
0277     // afterwards.
0278     void selectionPushOntoDocument (bool applySelTransparency = true);
0279 
0280     //
0281     // Same as image() but returns a _copy_ of the document image
0282     // + any (even non-image) selection pasted on top.
0283     //
0284     // Even if the selection has no content, it is still pasted:
0285     //
0286     // 1. For an image selection, this makes no difference.
0287     //
0288     // 2. For a text selection:
0289     //
0290     //    a) with an opaque background: the background rectangle is
0291     //      included -- this is necessary since the rectangle is visually
0292     //      there after all, and the intention of this method is to report
0293     //      everything.
0294     //
0295     //    b) with a transparent background: this makes no difference.
0296     //
0297     kpImage imageWithSelection () const;
0298 
0299 
0300     /*
0301      * Transformations
0302      * (convenience only - you could achieve the same effect (and more) with
0303      *  kpPixmapFX: these functions do not affect the selection)
0304      */
0305 
0306     void fill (const kpColor &color);
0307     void resize (int w, int h, const kpColor &backgroundColor);
0308 
0309 
0310 public Q_SLOTS:
0311     // these will emit signals!
0312     void slotContentsChanged (const QRect &rect);
0313     void slotSizeChanged (const QSize &newSize);
0314 
0315 Q_SIGNALS:
0316     void documentOpened ();
0317     void documentSaved ();
0318 
0319     // Emitted whenever the isModified() flag changes from false to true.
0320     // This is the _only_ signal that may be emitted in addition to the others.
0321     void documentModified ();
0322 
0323     void contentsChanged (const QRect &rect);
0324     void sizeChanged (int newWidth, int newHeight);  // see oldWidth(), oldHeight()
0325     void sizeChanged (const QSize &newSize);
0326 
0327     void selectionEnabled (bool on);
0328 
0329     // Emitted when setSelection() is given a selection such that we change
0330     // from a non-text-selection tool to the text selection tool or vice-versa.
0331     // <isText> reports whether the new selection is text (and therefore,
0332     // whether we've switched to the text tool).
0333     void selectionIsTextChanged (bool isText);
0334 
0335 private:
0336     int m_constructorWidth, m_constructorHeight;
0337     kpImage *m_image;
0338 
0339     QUrl m_url;
0340     bool m_isFromExistingURL;
0341     bool m_savedAtLeastOnceBefore;
0342 
0343     kpDocumentSaveOptions *m_saveOptions;
0344     kpDocumentMetaInfo *m_metaInfo;
0345 
0346     bool m_modified;
0347 
0348     kpAbstractSelection *m_selection;
0349 
0350     int m_oldWidth, m_oldHeight;
0351 
0352     // There is no need to maintain binary compatibility at this stage.
0353     // The d-pointer is just so that you can experiment without recompiling
0354     // the kitchen sink.
0355     struct kpDocumentPrivate *d;
0356 };
0357 
0358 
0359 #endif  // KP_DOCUMENT_H