3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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.
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.
29 #define DEBUG_KP_DOCUMENT 0
32 #include <kpDocument.h>
33 #include <kpDocumentPrivate.h>
52 #include <kio/netaccess.h>
54 #include <kmessagebox.h>
55 #include <kmimetype.h> // LOTODO: isn't this in KIO?
56 #include <ktemporaryfile.h>
59 #include <kpColorToolBar.h>
61 #include <kpDocumentEnvironment.h>
62 #include <kpDocumentSaveOptions.h>
63 #include <kpDocumentMetaInfo.h>
64 #include <kpEffectReduceColors.h>
65 #include <kpPixmapFX.h>
66 #include <kpAbstractSelection.h>
67 #include <kpAbstractImageSelection.h>
68 #include <kpTextSelection.h>
70 #include <kpToolToolBar.h>
74 kpAbstractSelection
*kpDocument::selection () const
80 kpAbstractImageSelection
*kpDocument::imageSelection () const
82 return dynamic_cast <kpAbstractImageSelection
*> (m_selection
);
86 kpTextSelection
*kpDocument::textSelection () const
88 return dynamic_cast <kpTextSelection
*> (m_selection
);
93 void kpDocument::setSelection (const kpAbstractSelection
&selection
)
95 #if DEBUG_KP_DOCUMENT && 1
96 kDebug () << "kpDocument::setSelection() sel boundingRect="
97 << selection
.boundingRect ()
101 d
->environ
->setQueueViewUpdates ();
103 const bool hadSelection
= (bool) m_selection
;
104 kpAbstractSelection
*oldSelection
= m_selection
;
107 // (must be called before giving the document a new selection, to
108 // avoid a potential mess where switchToCompatibleTool() ends
109 // the current selection tool, killing the new selection)
110 bool isTextChanged
= false;
111 d
->environ
->switchToCompatibleTool (selection
, &isTextChanged
);
112 Q_ASSERT (m_selection
== oldSelection
);
115 m_selection
= selection
.clone ();
117 // There's no need to uninitialize the old selection
118 // (e.g. call disconnect()) since we delete it later.
119 connect (m_selection
, SIGNAL (changed (const QRect
&)),
120 this, SLOT (slotContentsChanged (const QRect
&)));
124 // Now all kpDocument state has been set.
125 // We can _only_ change the environment after that, as the environment
126 // may access the document. Exception is above with
127 // switchToCompatibleTool().
130 d
->environ
->assertMatchingUIState (selection
);
134 // Now all kpDocument and environment state has been set.
135 // We can _only_ fire signals after that, as the signal receivers (the
136 // "wider environment") may access the document and the environment.
139 #if DEBUG_KP_DOCUMENT && 1
140 kDebug () << "\tcheck sel " << (int *) m_selection
141 << " boundingRect=" << m_selection
->boundingRect ()
146 if (oldSelection
->hasContent ())
147 slotContentsChanged (oldSelection
->boundingRect ());
149 emit
contentsChanged (oldSelection
->boundingRect ());
155 if (m_selection
->hasContent ())
156 slotContentsChanged (m_selection
->boundingRect ());
158 emit
contentsChanged (m_selection
->boundingRect ());
162 emit
selectionEnabled (true);
165 emit
selectionIsTextChanged (textSelection ());
167 d
->environ
->restoreQueueViewUpdates ();
169 #if DEBUG_KP_DOCUMENT && 1
170 kDebug () << "\tkpDocument::setSelection() ended";
175 kpImage
kpDocument::getSelectedBaseImage () const
177 kpAbstractImageSelection
*imageSel
= imageSelection ();
180 // Easy if we already have it :)
181 const kpImage image
= imageSel
->baseImage ();
182 if (!image
.isNull ())
186 const QRect boundingRect
= imageSel
->boundingRect ();
187 Q_ASSERT (boundingRect
.isValid ());
189 // OPT: This is very slow. Image / More Effects ... calls us twice
191 return imageSel
->givenImageMaskedByShape (getImageAt (boundingRect
));
195 void kpDocument::imageSelectionPullFromDocument (const kpColor
&backgroundColor
)
197 kpAbstractImageSelection
*imageSel
= imageSelection ();
200 // Should not already have an image or we would not be pulling.
201 Q_ASSERT (!imageSel
->hasContent ());
203 const QRect boundingRect
= imageSel
->boundingRect ();
204 Q_ASSERT (boundingRect
.isValid ());
208 // Get selection pixmap from document
211 kpImage selectedImage
= getSelectedBaseImage ();
213 d
->environ
->setQueueViewUpdates ();
215 imageSel
->setBaseImage (selectedImage
);
219 // Fill opaque bits of the hole in the document
222 #if !defined (QT_NO_DEBUG) && !defined (NDEBUG)
223 if (imageSel
->transparency ().isTransparent ())
225 Q_ASSERT (backgroundColor
== imageSel
->transparency ().transparentColor ());
229 // If this method is begin called by a tool, the assert does not
230 // have to hold since transparentColor() might not be defined in Opaque
233 // If we were called by a tricky sequence of undo/redo commands, the assert
234 // does not have to hold for additional reason, which is that
235 // kpMainWindow::setImageSelectionTransparency() does not have to
236 // set <backgroundColor> in Opaque Mode.
238 // In practice, it probably does hold but I wouldn't bet on it.
242 const kpImage selTransparentImage
= imageSel
->transparentImage ();
244 if (backgroundColor
.isOpaque ())
246 kpImage
eraseImage (boundingRect
.width (), boundingRect
.height ());
247 eraseImage
.fill (backgroundColor
.toQColor ());
249 if (kpPixmapFX::hasMask (selTransparentImage
))
250 eraseImage
.setMask (selTransparentImage
.mask ());
252 paintImageAt (eraseImage
, boundingRect
.topLeft ());
256 kpPixmapFX::paintMaskTransparentWithBrush (m_image
,
257 boundingRect
.topLeft (),
258 kpPixmapFX::getNonNullMask (selTransparentImage
));
259 slotContentsChanged (boundingRect
);
262 d
->environ
->restoreQueueViewUpdates ();
266 void kpDocument::selectionDelete ()
268 Q_ASSERT (m_selection
);
270 const QRect boundingRect
= m_selection
->boundingRect ();
271 Q_ASSERT (boundingRect
.isValid ());
273 const bool selectionHadContent
= m_selection
->hasContent ();
279 // HACK to prevent document from being modified when
280 // user cancels dragging out a new selection
281 // REFACTOR: Extract this out into a method.
282 if (selectionHadContent
)
283 slotContentsChanged (boundingRect
);
285 emit
contentsChanged (boundingRect
);
287 emit
selectionEnabled (false);
291 void kpDocument::selectionCopyOntoDocument (bool applySelTransparency
)
293 Q_ASSERT (m_selection
);
294 Q_ASSERT (m_selection
->hasContent ());
296 const QRect boundingRect
= m_selection
->boundingRect ();
297 Q_ASSERT (boundingRect
.isValid ());
299 if (imageSelection ())
301 if (applySelTransparency
)
302 imageSelection ()->paint (m_image
, rect ());
304 imageSelection ()->paintWithBaseImage (m_image
, rect ());
308 // (for antialiasing with background)
309 m_selection
->paint (m_image
, rect ());
312 slotContentsChanged (boundingRect
);
316 void kpDocument::selectionPushOntoDocument (bool applySelTransparency
)
318 selectionCopyOntoDocument (applySelTransparency
);
323 kpImage
kpDocument::imageWithSelection () const
325 #if DEBUG_KP_DOCUMENT && 1
326 kDebug () << "kpDocument::imageWithSelection()";
331 // It need not have any content because e.g. a text box with an opaque
332 // background, but no content, is still visually there.
335 #if DEBUG_KP_DOCUMENT && 1
336 kDebug () << "\tselection @ " << m_selection
->boundingRect ();
338 kpImage output
= *m_image
;
340 // (this is a NOP for image selections without content)
341 m_selection
->paint (&output
, rect ());
347 #if DEBUG_KP_DOCUMENT && 1
348 kDebug () << "\tno selection";