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