TDE graphics utilities
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

1540 lines
42KB

  1. /*
  2. Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions
  6. are met:
  7. 1. Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  13. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  14. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  15. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  16. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  17. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  18. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #define DEBUG_KP_DOCUMENT 0
  24. #include <kpdocument.h>
  25. #include <math.h>
  26. #include <tqcolor.h>
  27. #include <tqbitmap.h>
  28. #include <tqbrush.h>
  29. #include <tqfile.h>
  30. #include <tqimage.h>
  31. #include <tqpixmap.h>
  32. #include <tqpainter.h>
  33. #include <tqrect.h>
  34. #include <tqsize.h>
  35. #include <tqvaluelist.h>
  36. #include <tqwmatrix.h>
  37. #include <kdebug.h>
  38. #include <tdeglobal.h>
  39. #include <kimageio.h>
  40. #include <tdeio/netaccess.h>
  41. #include <tdelocale.h>
  42. #include <tdemessagebox.h>
  43. #include <kmimetype.h>
  44. #include <ksavefile.h>
  45. #include <tdetempfile.h>
  46. #include <kpcolor.h>
  47. #include <kpcolortoolbar.h>
  48. #include <kpdefs.h>
  49. #include <kpdocumentsaveoptions.h>
  50. #include <kpdocumentmetainfo.h>
  51. #include <kpeffectreducecolors.h>
  52. #include <kpmainwindow.h>
  53. #include <kppixmapfx.h>
  54. #include <kpselection.h>
  55. #include <kptool.h>
  56. #include <kptooltoolbar.h>
  57. #include <kpviewmanager.h>
  58. struct kpDocumentPrivate
  59. {
  60. kpDocumentPrivate ()
  61. {
  62. }
  63. };
  64. kpDocument::kpDocument (int w, int h, kpMainWindow *mainWindow)
  65. : m_constructorWidth (w), m_constructorHeight (h),
  66. m_mainWindow (mainWindow),
  67. m_isFromURL (false),
  68. m_savedAtLeastOnceBefore (false),
  69. m_saveOptions (new kpDocumentSaveOptions ()),
  70. m_metaInfo (new kpDocumentMetaInfo ()),
  71. m_modified (false),
  72. m_selection (0),
  73. m_oldWidth (-1), m_oldHeight (-1),
  74. d (new kpDocumentPrivate ())
  75. {
  76. #if DEBUG_KP_DOCUMENT && 0
  77. kdDebug () << "kpDocument::kpDocument (" << w << "," << h << ")" << endl;
  78. #endif
  79. m_pixmap = new TQPixmap (w, h);
  80. m_pixmap->fill (TQt::white);
  81. }
  82. kpDocument::~kpDocument ()
  83. {
  84. delete d;
  85. delete m_pixmap;
  86. delete m_saveOptions;
  87. delete m_metaInfo;
  88. delete m_selection;
  89. }
  90. kpMainWindow *kpDocument::mainWindow () const
  91. {
  92. return m_mainWindow;
  93. }
  94. void kpDocument::setMainWindow (kpMainWindow *mainWindow)
  95. {
  96. m_mainWindow = mainWindow;
  97. }
  98. /*
  99. * File I/O
  100. */
  101. // public static
  102. TQPixmap kpDocument::convertToPixmapAsLosslessAsPossible (
  103. const TQImage &image,
  104. const kpPixmapFX::WarnAboutLossInfo &wali,
  105. kpDocumentSaveOptions *saveOptions,
  106. kpDocumentMetaInfo *metaInfo)
  107. {
  108. if (image.isNull ())
  109. return TQPixmap ();
  110. #if DEBUG_KP_DOCUMENT
  111. kdDebug () << "\timage: depth=" << image.depth ()
  112. << " (X display=" << TQColor::numBitPlanes () << ")"
  113. << " hasAlphaBuffer=" << image.hasAlphaBuffer ()
  114. << endl;
  115. #endif
  116. if (saveOptions)
  117. {
  118. saveOptions->setColorDepth (image.depth ());
  119. saveOptions->setDither (false); // avoid double dithering when saving
  120. }
  121. if (metaInfo)
  122. {
  123. metaInfo->setDotsPerMeterX (image.dotsPerMeterX ());
  124. metaInfo->setDotsPerMeterY (image.dotsPerMeterY ());
  125. metaInfo->setOffset (image.offset ());
  126. TQValueList <TQImageTextKeyLang> keyList = image.textList ();
  127. for (TQValueList <TQImageTextKeyLang>::const_iterator it = keyList.begin ();
  128. it != keyList.end ();
  129. it++)
  130. {
  131. metaInfo->setText (*it, image.text (*it));
  132. }
  133. #if DEBUG_KP_DOCUMENT
  134. metaInfo->printDebug ("\tmetaInfo");
  135. #endif
  136. }
  137. #if DEBUG_KP_DOCUMENT && 1
  138. {
  139. if (image.width () <= 16 && image.height () <= 16)
  140. {
  141. kdDebug () << "Image dump:" << endl;
  142. for (int y = 0; y < image.height (); y++)
  143. {
  144. for (int x = 0; x < image.width (); x++)
  145. {
  146. const TQRgb rgb = image.pixel (x, y);
  147. fprintf (stderr, " %08X", rgb);
  148. }
  149. fprintf (stderr, "\n");
  150. }
  151. }
  152. }
  153. #endif
  154. TQPixmap newPixmap = kpPixmapFX::convertToPixmapAsLosslessAsPossible (image, wali);
  155. #if DEBUG_KP_DOCUMENT && 1
  156. {
  157. const TQImage image2 = kpPixmapFX::convertToImage (newPixmap);
  158. kdDebug () << "(Converted to pixmap) Image dump:" << endl;
  159. bool differsFromOrgImage = false;
  160. unsigned long hash = 0;
  161. int numDiff = 0;
  162. for (int y = 0; y < image2.height (); y++)
  163. {
  164. for (int x = 0; x < image2.width (); x++)
  165. {
  166. const TQRgb rgb = image2.pixel (x, y);
  167. hash += ((x % 2) + 1) * rgb;
  168. if (rgb != image.pixel (x, y))
  169. {
  170. differsFromOrgImage = true;
  171. numDiff++;
  172. }
  173. if (image2.width () <= 16 && image2.height () <= 16)
  174. fprintf (stderr, " %08X", rgb);
  175. }
  176. if (image2.width () <= 16 && image2.height () <= 16)
  177. fprintf (stderr, "\n");
  178. }
  179. kdDebug () << "\tdiffersFromOrgImage="
  180. << differsFromOrgImage
  181. << " numDiff="
  182. << numDiff
  183. << " hash=" << hash << endl;
  184. }
  185. #endif
  186. return newPixmap;
  187. }
  188. // public static
  189. TQPixmap kpDocument::getPixmapFromFile (const KURL &url, bool suppressDoesntExistDialog,
  190. TQWidget *parent,
  191. kpDocumentSaveOptions *saveOptions,
  192. kpDocumentMetaInfo *metaInfo)
  193. {
  194. #if DEBUG_KP_DOCUMENT
  195. kdDebug () << "kpDocument::getPixmapFromFile(" << url << "," << parent << ")" << endl;
  196. #endif
  197. if (saveOptions)
  198. *saveOptions = kpDocumentSaveOptions ();
  199. if (metaInfo)
  200. *metaInfo = kpDocumentMetaInfo ();
  201. TQString tempFile;
  202. if (url.isEmpty () || !TDEIO::NetAccess::download (url, tempFile, parent))
  203. {
  204. if (!suppressDoesntExistDialog)
  205. {
  206. KMessageBox::sorry (parent,
  207. i18n ("Could not open \"%1\".")
  208. .arg (kpDocument::prettyFilenameForURL (url)));
  209. }
  210. return TQPixmap ();
  211. }
  212. TQImage image;
  213. // sync: remember to "TDEIO::NetAccess::removeTempFile (tempFile)" in all exit paths
  214. {
  215. TQString detectedMimeType = KImageIO::mimeType (tempFile);
  216. if (saveOptions)
  217. saveOptions->setMimeType (detectedMimeType);
  218. #if DEBUG_KP_DOCUMENT
  219. kdDebug () << "\ttempFile=" << tempFile << endl;
  220. kdDebug () << "\tmimetype=" << detectedMimeType << endl;
  221. kdDebug () << "\tsrc=" << url.path () << endl;
  222. kdDebug () << "\tmimetype of src=" << KImageIO::mimeType (url.path ()) << endl;
  223. #endif
  224. if (detectedMimeType.isEmpty ())
  225. {
  226. KMessageBox::sorry (parent,
  227. i18n ("Could not open \"%1\" - unknown mimetype.")
  228. .arg (kpDocument::prettyFilenameForURL (url)));
  229. TDEIO::NetAccess::removeTempFile (tempFile);
  230. return TQPixmap ();
  231. }
  232. image = TQImage (tempFile);
  233. TDEIO::NetAccess::removeTempFile (tempFile);
  234. }
  235. if (image.isNull ())
  236. {
  237. KMessageBox::sorry (parent,
  238. i18n ("Could not open \"%1\" - unsupported image format.\n"
  239. "The file may be corrupt.")
  240. .arg (kpDocument::prettyFilenameForURL (url)));
  241. return TQPixmap ();
  242. }
  243. const TQPixmap newPixmap = kpDocument::convertToPixmapAsLosslessAsPossible (image,
  244. kpPixmapFX::WarnAboutLossInfo (
  245. i18n ("The image \"%1\""
  246. " may have more colors than the current screen mode."
  247. " In order to display it, some colors may be changed."
  248. " Try increasing your screen depth to at least %2bpp."
  249. "\nIt also"
  250. " contains translucency which is not fully"
  251. " supported. The translucency data will be"
  252. " approximated with a 1-bit transparency mask.")
  253. .arg (prettyFilenameForURL (url)),
  254. i18n ("The image \"%1\""
  255. " may have more colors than the current screen mode."
  256. " In order to display it, some colors may be changed."
  257. " Try increasing your screen depth to at least %2bpp.")
  258. .arg (prettyFilenameForURL (url)),
  259. i18n ("The image \"%1\""
  260. " contains translucency which is not fully"
  261. " supported. The translucency data will be"
  262. " approximated with a 1-bit transparency mask.")
  263. .arg (prettyFilenameForURL (url)),
  264. "docOpen",
  265. parent),
  266. saveOptions,
  267. metaInfo);
  268. if (newPixmap.isNull ())
  269. {
  270. KMessageBox::sorry (parent,
  271. i18n ("Could not open \"%1\" - out of graphics memory.")
  272. .arg (kpDocument::prettyFilenameForURL (url)));
  273. return TQPixmap ();
  274. }
  275. #if DEBUG_KP_DOCUMENT
  276. kdDebug () << "\tpixmap: depth=" << newPixmap.depth ()
  277. << " hasAlphaChannelOrMask=" << newPixmap.hasAlpha ()
  278. << " hasAlphaChannel=" << newPixmap.hasAlphaChannel ()
  279. << endl;
  280. #endif
  281. return newPixmap;
  282. }
  283. void kpDocument::openNew (const KURL &url)
  284. {
  285. #if DEBUG_KP_DOCUMENT
  286. kdDebug () << "KpDocument::openNew (" << url << ")" << endl;
  287. #endif
  288. m_pixmap->fill (TQt::white);
  289. setURL (url, false/*not from url*/);
  290. *m_saveOptions = kpDocumentSaveOptions ();
  291. *m_metaInfo = kpDocumentMetaInfo ();
  292. m_modified = false;
  293. emit documentOpened ();
  294. }
  295. bool kpDocument::open (const KURL &url, bool newDocSameNameIfNotExist)
  296. {
  297. #if DEBUG_KP_DOCUMENT
  298. kdDebug () << "kpDocument::open (" << url << ")" << endl;
  299. #endif
  300. kpDocumentSaveOptions newSaveOptions;
  301. kpDocumentMetaInfo newMetaInfo;
  302. TQPixmap newPixmap = kpDocument::getPixmapFromFile (url,
  303. newDocSameNameIfNotExist/*suppress "doesn't exist" dialog*/,
  304. m_mainWindow,
  305. &newSaveOptions,
  306. &newMetaInfo);
  307. if (!newPixmap.isNull ())
  308. {
  309. delete m_pixmap;
  310. m_pixmap = new TQPixmap (newPixmap);
  311. setURL (url, true/*is from url*/);
  312. *m_saveOptions = newSaveOptions;
  313. *m_metaInfo = newMetaInfo;
  314. m_modified = false;
  315. emit documentOpened ();
  316. return true;
  317. }
  318. if (newDocSameNameIfNotExist)
  319. {
  320. if (!url.isEmpty () &&
  321. // not just a permission error?
  322. !TDEIO::NetAccess::exists (url, true/*open*/, m_mainWindow))
  323. {
  324. openNew (url);
  325. }
  326. else
  327. {
  328. openNew (KURL ());
  329. }
  330. return true;
  331. }
  332. else
  333. {
  334. return false;
  335. }
  336. }
  337. bool kpDocument::save (bool overwritePrompt, bool lossyPrompt)
  338. {
  339. #if DEBUG_KP_DOCUMENT
  340. kdDebug () << "kpDocument::save("
  341. << "overwritePrompt=" << overwritePrompt
  342. << ",lossyPrompt=" << lossyPrompt
  343. << ") url=" << m_url
  344. << " savedAtLeastOnceBefore=" << savedAtLeastOnceBefore ()
  345. << endl;
  346. #endif
  347. // TODO: check feels weak
  348. if (m_url.isEmpty () || m_saveOptions->mimeType ().isEmpty ())
  349. {
  350. KMessageBox::detailedError (m_mainWindow,
  351. i18n ("Could not save image - insufficient information."),
  352. i18n ("URL: %1\n"
  353. "Mimetype: %2")
  354. .arg (prettyURL ())
  355. .arg (m_saveOptions->mimeType ().isEmpty () ?
  356. i18n ("<empty>") :
  357. m_saveOptions->mimeType ()),
  358. i18n ("Internal Error"));
  359. return false;
  360. }
  361. return saveAs (m_url, *m_saveOptions,
  362. overwritePrompt,
  363. lossyPrompt);
  364. }
  365. // public static
  366. bool kpDocument::lossyPromptContinue (const TQPixmap &pixmap,
  367. const kpDocumentSaveOptions &saveOptions,
  368. TQWidget *parent)
  369. {
  370. #if DEBUG_KP_DOCUMENT
  371. kdDebug () << "kpDocument::lossyPromptContinue()" << endl;
  372. #endif
  373. #define QUIT_IF_CANCEL(messageBoxCommand) \
  374. { \
  375. if (messageBoxCommand != KMessageBox::Continue) \
  376. { \
  377. return false; \
  378. } \
  379. }
  380. const int lossyType = saveOptions.isLossyForSaving (pixmap);
  381. if (lossyType & (kpDocumentSaveOptions::MimeTypeMaximumColorDepthLow |
  382. kpDocumentSaveOptions::Quality))
  383. {
  384. QUIT_IF_CANCEL (
  385. KMessageBox::warningContinueCancel (parent,
  386. i18n ("<qt><p>The <b>%1</b> format may not be able"
  387. " to preserve all of the image's color information.</p>"
  388. "<p>Are you sure you want to save in this format?</p></qt>")
  389. .arg (KMimeType::mimeType (saveOptions.mimeType ())->comment ()),
  390. // TODO: caption misleading for lossless formats that have
  391. // low maximum colour depth
  392. i18n ("Lossy File Format"),
  393. KStdGuiItem::save (),
  394. TQString::fromLatin1 ("SaveInLossyMimeTypeDontAskAgain")));
  395. }
  396. else if (lossyType & kpDocumentSaveOptions::ColorDepthLow)
  397. {
  398. QUIT_IF_CANCEL (
  399. KMessageBox::warningContinueCancel (parent,
  400. i18n ("<qt><p>Saving the image at the low color depth of %1-bit"
  401. " may result in the loss of color information."
  402. " Any transparency will also be removed.</p>"
  403. "<p>Are you sure you want to save at this color depth?</p></qt>")
  404. .arg (saveOptions.colorDepth ()),
  405. i18n ("Low Color Depth"),
  406. KStdGuiItem::save (),
  407. TQString::fromLatin1 ("SaveAtLowColorDepthDontAskAgain")));
  408. }
  409. #undef QUIT_IF_CANCEL
  410. return true;
  411. }
  412. // public static
  413. bool kpDocument::savePixmapToDevice (const TQPixmap &pixmap,
  414. TQIODevice *device,
  415. const kpDocumentSaveOptions &saveOptions,
  416. const kpDocumentMetaInfo &metaInfo,
  417. bool lossyPrompt,
  418. TQWidget *parent,
  419. bool *userCancelled)
  420. {
  421. if (userCancelled)
  422. *userCancelled = false;
  423. TQString type = KImageIO::typeForMime (saveOptions.mimeType ());
  424. #if DEBUG_KP_DOCUMENT
  425. kdDebug () << "\tmimeType=" << saveOptions.mimeType ()
  426. << " type=" << type << endl;
  427. #endif
  428. if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent))
  429. {
  430. if (userCancelled)
  431. *userCancelled = true;
  432. #if DEBUG_KP_DOCUMENT
  433. kdDebug () << "\treturning false because of lossyPrompt" << endl;
  434. #endif
  435. return false;
  436. }
  437. TQPixmap pixmapToSave =
  438. kpPixmapFX::pixmapWithDefinedTransparentPixels (pixmap,
  439. TQt::white); // CONFIG
  440. TQImage imageToSave = kpPixmapFX::convertToImage (pixmapToSave);
  441. // TODO: fix dup with kpDocumentSaveOptions::isLossyForSaving()
  442. const bool useSaveOptionsColorDepth =
  443. (saveOptions.mimeTypeHasConfigurableColorDepth () &&
  444. !saveOptions.colorDepthIsInvalid ());
  445. const bool useSaveOptionsQuality =
  446. (saveOptions.mimeTypeHasConfigurableQuality () &&
  447. !saveOptions.qualityIsInvalid ());
  448. //
  449. // Reduce colors if required
  450. //
  451. if (useSaveOptionsColorDepth &&
  452. imageToSave.depth () != saveOptions.colorDepth ())
  453. {
  454. imageToSave = ::convertImageDepth (imageToSave,
  455. saveOptions.colorDepth (),
  456. saveOptions.dither ());
  457. }
  458. //
  459. // Write Meta Info
  460. //
  461. imageToSave.setDotsPerMeterX (metaInfo.dotsPerMeterX ());
  462. imageToSave.setDotsPerMeterY (metaInfo.dotsPerMeterY ());
  463. imageToSave.setOffset (metaInfo.offset ());
  464. TQValueList <TQImageTextKeyLang> keyList = metaInfo.textList ();
  465. for (TQValueList <TQImageTextKeyLang>::const_iterator it = keyList.begin ();
  466. it != keyList.end ();
  467. it++)
  468. {
  469. imageToSave.setText ((*it).key, (*it).lang, metaInfo.text (*it));
  470. }
  471. //
  472. // Save at required quality
  473. //
  474. int quality = -1; // default
  475. if (useSaveOptionsQuality)
  476. quality = saveOptions.quality ();
  477. if (!imageToSave.save (device, type.latin1 (), quality))
  478. {
  479. #if DEBUG_KP_DOCUMENT
  480. kdDebug () << "\tTQImage::save() returned false" << endl;
  481. #endif
  482. return false;
  483. }
  484. #if DEBUG_KP_DOCUMENT
  485. kdDebug () << "\tsave OK" << endl;
  486. #endif
  487. return true;
  488. }
  489. static void CouldNotCreateTemporaryFileDialog (TQWidget *parent)
  490. {
  491. KMessageBox::error (parent,
  492. i18n ("Could not save image - unable to create temporary file."));
  493. }
  494. static void CouldNotSaveDialog (const KURL &url, TQWidget *parent)
  495. {
  496. // TODO: use file.errorString()
  497. KMessageBox::error (parent,
  498. i18n ("Could not save as \"%1\".")
  499. .arg (kpDocument::prettyFilenameForURL (url)));
  500. }
  501. // public static
  502. bool kpDocument::savePixmapToFile (const TQPixmap &pixmap,
  503. const KURL &url,
  504. const kpDocumentSaveOptions &saveOptions,
  505. const kpDocumentMetaInfo &metaInfo,
  506. bool overwritePrompt,
  507. bool lossyPrompt,
  508. TQWidget *parent)
  509. {
  510. // TODO: Use TDEIO::NetAccess:mostLocalURL() for accessing home:/ (and other
  511. // such local URLs) for efficiency and because only local writes
  512. // are atomic.
  513. #if DEBUG_KP_DOCUMENT
  514. kdDebug () << "kpDocument::savePixmapToFile ("
  515. << url
  516. << ",overwritePrompt=" << overwritePrompt
  517. << ",lossyPrompt=" << lossyPrompt
  518. << ")" << endl;
  519. saveOptions.printDebug (TQString::fromLatin1 ("\tsaveOptions"));
  520. metaInfo.printDebug (TQString::fromLatin1 ("\tmetaInfo"));
  521. #endif
  522. if (overwritePrompt && TDEIO::NetAccess::exists (url, false/*write*/, parent))
  523. {
  524. int result = KMessageBox::warningContinueCancel (parent,
  525. i18n ("A document called \"%1\" already exists.\n"
  526. "Do you want to overwrite it?")
  527. .arg (prettyFilenameForURL (url)),
  528. TQString(),
  529. i18n ("Overwrite"));
  530. if (result != KMessageBox::Continue)
  531. {
  532. #if DEBUG_KP_DOCUMENT
  533. kdDebug () << "\tuser doesn't want to overwrite" << endl;
  534. #endif
  535. return false;
  536. }
  537. }
  538. if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent))
  539. {
  540. #if DEBUG_KP_DOCUMENT
  541. kdDebug () << "\treturning false because of lossyPrompt" << endl;
  542. #endif
  543. return false;
  544. }
  545. // Local file?
  546. if (url.isLocalFile ())
  547. {
  548. const TQString filename = url.path ();
  549. // sync: All failure exit paths _must_ call KSaveFile::abort() or
  550. // else, the KSaveFile destructor will overwrite the file,
  551. // <filename>, despite the failure.
  552. KSaveFile atomicFileWriter (filename);
  553. {
  554. if (atomicFileWriter.status () != 0)
  555. {
  556. // We probably don't need this as <filename> has not been
  557. // opened.
  558. atomicFileWriter.abort ();
  559. #if DEBUG_KP_DOCUMENT
  560. kdDebug () << "\treturning false because could not open KSaveFile"
  561. << " status=" << atomicFileWriter.status () << endl;
  562. #endif
  563. ::CouldNotCreateTemporaryFileDialog (parent);
  564. return false;
  565. }
  566. // Write to local temporary file.
  567. if (!savePixmapToDevice (pixmap, TQT_TQIODEVICE(atomicFileWriter.file ()),
  568. saveOptions, metaInfo,
  569. false/*no lossy prompt*/,
  570. parent))
  571. {
  572. atomicFileWriter.abort ();
  573. #if DEBUG_KP_DOCUMENT
  574. kdDebug () << "\treturning false because could not save pixmap to device"
  575. << endl;
  576. #endif
  577. ::CouldNotSaveDialog (url, parent);
  578. return false;
  579. }
  580. // Atomically overwrite local file with the temporary file
  581. // we saved to.
  582. if (!atomicFileWriter.close ())
  583. {
  584. atomicFileWriter.abort ();
  585. #if DEBUG_KP_DOCUMENT
  586. kdDebug () << "\tcould not close KSaveFile" << endl;
  587. #endif
  588. ::CouldNotSaveDialog (url, parent);
  589. return false;
  590. }
  591. } // sync KSaveFile.abort()
  592. }
  593. // Remote file?
  594. else
  595. {
  596. // Create temporary file that is deleted when the variable goes
  597. // out of scope.
  598. KTempFile tempFile;
  599. tempFile.setAutoDelete (true);
  600. TQString filename = tempFile.name ();
  601. if (filename.isEmpty ())
  602. {
  603. #if DEBUG_KP_DOCUMENT
  604. kdDebug () << "\treturning false because tempFile empty" << endl;
  605. #endif
  606. ::CouldNotCreateTemporaryFileDialog (parent);
  607. return false;
  608. }
  609. // Write to local temporary file.
  610. TQFile file (filename);
  611. {
  612. if (!file.open (IO_WriteOnly))
  613. {
  614. #if DEBUG_KP_DOCUMENT
  615. kdDebug () << "\treturning false because can't open file"
  616. << " errorString=" << file.errorString () << endl;
  617. #endif
  618. ::CouldNotCreateTemporaryFileDialog (parent);
  619. return false;
  620. }
  621. if (!savePixmapToDevice (pixmap, TQT_TQIODEVICE(&file),
  622. saveOptions, metaInfo,
  623. false/*no lossy prompt*/,
  624. parent))
  625. {
  626. #if DEBUG_KP_DOCUMENT
  627. kdDebug () << "\treturning false because could not save pixmap to device"
  628. << endl;
  629. #endif
  630. ::CouldNotSaveDialog (url, parent);
  631. return false;
  632. }
  633. }
  634. file.close ();
  635. if (file.status () != IO_Ok)
  636. {
  637. #if DEBUG_KP_DOCUMENT
  638. kdDebug () << "\treturning false because could not close" << endl;
  639. #endif
  640. ::CouldNotSaveDialog (url, parent);
  641. return false;
  642. }
  643. // Copy local temporary file to overwrite remote.
  644. // TODO: No one seems to know how to do this atomically
  645. // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2].
  646. // At least, fish:// (ssh) is definitely not atomic.
  647. if (!TDEIO::NetAccess::upload (filename, url, parent))
  648. {
  649. #if DEBUG_KP_DOCUMENT
  650. kdDebug () << "\treturning false because could not upload" << endl;
  651. #endif
  652. KMessageBox::error (parent,
  653. i18n ("Could not save image - failed to upload."));
  654. return false;
  655. }
  656. }
  657. return true;
  658. }
  659. bool kpDocument::saveAs (const KURL &url,
  660. const kpDocumentSaveOptions &saveOptions,
  661. bool overwritePrompt,
  662. bool lossyPrompt)
  663. {
  664. #if DEBUG_KP_DOCUMENT
  665. kdDebug () << "kpDocument::saveAs (" << url << ","
  666. << saveOptions.mimeType () << ")" << endl;
  667. #endif
  668. if (kpDocument::savePixmapToFile (pixmapWithSelection (),
  669. url,
  670. saveOptions, *metaInfo (),
  671. overwritePrompt,
  672. lossyPrompt,
  673. m_mainWindow))
  674. {
  675. setURL (url, true/*is from url*/);
  676. *m_saveOptions = saveOptions;
  677. m_modified = false;
  678. m_savedAtLeastOnceBefore = true;
  679. emit documentSaved ();
  680. return true;
  681. }
  682. else
  683. {
  684. return false;
  685. }
  686. }
  687. // public
  688. bool kpDocument::savedAtLeastOnceBefore () const
  689. {
  690. return m_savedAtLeastOnceBefore;
  691. }
  692. // public
  693. KURL kpDocument::url () const
  694. {
  695. return m_url;
  696. }
  697. // public
  698. void kpDocument::setURL (const KURL &url, bool isFromURL)
  699. {
  700. m_url = url;
  701. m_isFromURL = isFromURL;
  702. }
  703. // public
  704. bool kpDocument::isFromURL (bool checkURLStillExists) const
  705. {
  706. if (!m_isFromURL)
  707. return false;
  708. if (!checkURLStillExists)
  709. return true;
  710. return (!m_url.isEmpty () &&
  711. TDEIO::NetAccess::exists (m_url, true/*open*/, m_mainWindow));
  712. }
  713. // static
  714. TQString kpDocument::prettyURLForURL (const KURL &url)
  715. {
  716. if (url.isEmpty ())
  717. return i18n ("Untitled");
  718. else
  719. return url.prettyURL (0, KURL::StripFileProtocol);
  720. }
  721. TQString kpDocument::prettyURL () const
  722. {
  723. return prettyURLForURL (m_url);
  724. }
  725. // static
  726. TQString kpDocument::prettyFilenameForURL (const KURL &url)
  727. {
  728. if (url.isEmpty ())
  729. return i18n ("Untitled");
  730. else if (url.fileName ().isEmpty ())
  731. return prettyURLForURL (url); // better than the name ""
  732. else
  733. return url.fileName ();
  734. }
  735. TQString kpDocument::prettyFilename () const
  736. {
  737. return prettyFilenameForURL (m_url);
  738. }
  739. // public
  740. const kpDocumentSaveOptions *kpDocument::saveOptions () const
  741. {
  742. return m_saveOptions;
  743. }
  744. // public
  745. void kpDocument::setSaveOptions (const kpDocumentSaveOptions &saveOptions)
  746. {
  747. *m_saveOptions = saveOptions;
  748. }
  749. // public
  750. const kpDocumentMetaInfo *kpDocument::metaInfo () const
  751. {
  752. return m_metaInfo;
  753. }
  754. // public
  755. void kpDocument::setMetaInfo (const kpDocumentMetaInfo &metaInfo)
  756. {
  757. *m_metaInfo = metaInfo;
  758. }
  759. /*
  760. * Properties
  761. */
  762. void kpDocument::setModified (bool yes)
  763. {
  764. if (yes == m_modified)
  765. return;
  766. m_modified = yes;
  767. if (yes)
  768. emit documentModified ();
  769. }
  770. bool kpDocument::isModified () const
  771. {
  772. return m_modified;
  773. }
  774. bool kpDocument::isEmpty () const
  775. {
  776. return url ().isEmpty () && !isModified ();
  777. }
  778. int kpDocument::constructorWidth () const
  779. {
  780. return m_constructorWidth;
  781. }
  782. int kpDocument::width (bool ofSelection) const
  783. {
  784. if (ofSelection && m_selection)
  785. return m_selection->width ();
  786. else
  787. return m_pixmap->width ();
  788. }
  789. int kpDocument::oldWidth () const
  790. {
  791. return m_oldWidth;
  792. }
  793. void kpDocument::setWidth (int w, const kpColor &backgroundColor)
  794. {
  795. resize (w, height (), backgroundColor);
  796. }
  797. int kpDocument::constructorHeight () const
  798. {
  799. return m_constructorHeight;
  800. }
  801. int kpDocument::height (bool ofSelection) const
  802. {
  803. if (ofSelection && m_selection)
  804. return m_selection->height ();
  805. else
  806. return m_pixmap->height ();
  807. }
  808. int kpDocument::oldHeight () const
  809. {
  810. return m_oldHeight;
  811. }
  812. void kpDocument::setHeight (int h, const kpColor &backgroundColor)
  813. {
  814. resize (width (), h, backgroundColor);
  815. }
  816. TQRect kpDocument::rect (bool ofSelection) const
  817. {
  818. if (ofSelection && m_selection)
  819. return m_selection->boundingRect ();
  820. else
  821. return m_pixmap->rect ();
  822. }
  823. /*
  824. * Pixmap access
  825. */
  826. // public
  827. TQPixmap kpDocument::getPixmapAt (const TQRect &rect) const
  828. {
  829. return kpPixmapFX::getPixmapAt (*m_pixmap, rect);
  830. }
  831. // public
  832. void kpDocument::setPixmapAt (const TQPixmap &pixmap, const TQPoint &at)
  833. {
  834. #if DEBUG_KP_DOCUMENT && 0
  835. kdDebug () << "kpDocument::setPixmapAt (pixmap (w="
  836. << pixmap.width ()
  837. << ",h=" << pixmap.height ()
  838. << "), x=" << at.x ()
  839. << ",y=" << at.y ()
  840. << endl;
  841. #endif
  842. kpPixmapFX::setPixmapAt (m_pixmap, at, pixmap);
  843. slotContentsChanged (TQRect (at.x (), at.y (), pixmap.width (), pixmap.height ()));
  844. }
  845. // public
  846. void kpDocument::paintPixmapAt (const TQPixmap &pixmap, const TQPoint &at)
  847. {
  848. kpPixmapFX::paintPixmapAt (m_pixmap, at, pixmap);
  849. slotContentsChanged (TQRect (at.x (), at.y (), pixmap.width (), pixmap.height ()));
  850. }
  851. // public
  852. TQPixmap *kpDocument::pixmap (bool ofSelection) const
  853. {
  854. if (ofSelection)
  855. {
  856. if (m_selection && m_selection->pixmap ())
  857. return m_selection->pixmap ();
  858. else
  859. return 0;
  860. }
  861. else
  862. return m_pixmap;
  863. }
  864. // public
  865. void kpDocument::setPixmap (const TQPixmap &pixmap)
  866. {
  867. m_oldWidth = width (), m_oldHeight = height ();
  868. *m_pixmap = pixmap;
  869. if (m_oldWidth == width () && m_oldHeight == height ())
  870. slotContentsChanged (pixmap.rect ());
  871. else
  872. slotSizeChanged (width (), height ());
  873. }
  874. // public
  875. void kpDocument::setPixmap (bool ofSelection, const TQPixmap &pixmap)
  876. {
  877. if (ofSelection)
  878. {
  879. if (!m_selection)
  880. {
  881. kdError () << "kpDocument::setPixmap(ofSelection=true) without sel" << endl;
  882. return;
  883. }
  884. m_selection->setPixmap (pixmap);
  885. }
  886. else
  887. setPixmap (pixmap);
  888. }
  889. // private
  890. void kpDocument::updateToolsSingleKeyTriggersEnabled ()
  891. {
  892. if (m_mainWindow)
  893. {
  894. // Disable single key shortcuts when the user is editing text
  895. m_mainWindow->enableActionsSingleKeyTriggers (!m_selection || !m_selection->isText ());
  896. }
  897. }
  898. // public
  899. kpSelection *kpDocument::selection () const
  900. {
  901. return m_selection;
  902. }
  903. // public
  904. void kpDocument::setSelection (const kpSelection &selection)
  905. {
  906. #if DEBUG_KP_DOCUMENT && 0
  907. kdDebug () << "kpDocument::setSelection() sel boundingRect="
  908. << selection.boundingRect ()
  909. << endl;
  910. #endif
  911. kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
  912. if (vm)
  913. vm->setQueueUpdates ();
  914. bool hadSelection = (bool) m_selection;
  915. const bool isTextChanged = (m_mainWindow->toolIsTextTool () !=
  916. (selection.type () == kpSelection::Text));
  917. // We don't change the Selection Tool if the new selection's
  918. // shape is merely different to the current tool's (e.g. rectangular
  919. // vs elliptical) because:
  920. //
  921. // 1. All image selection tools support editing selections of all the
  922. // different shapes anyway.
  923. // 2. Suppose the user is trying out different drags of selection borders
  924. // and then decides to paste a differently shaped selection before continuing
  925. // to try out different borders. If the pasting were to switch to
  926. // a differently shaped tool, the borders drawn after the paste would
  927. // be using a new shape rather than the shape before the paste. This
  928. // could get irritating so we don't do the switch.
  929. //
  930. if (m_mainWindow &&
  931. (!m_mainWindow->toolIsASelectionTool () || isTextChanged))
  932. {
  933. // Switch to the appropriately shaped selection tool
  934. // _before_ we change the selection
  935. // (all selection tool's ::end() functions nuke the current selection)
  936. switch (selection.type ())
  937. {
  938. case kpSelection::Rectangle:
  939. m_mainWindow->slotToolRectSelection ();
  940. break;
  941. case kpSelection::Ellipse:
  942. m_mainWindow->slotToolEllipticalSelection ();
  943. break;
  944. case kpSelection::Points:
  945. m_mainWindow->slotToolFreeFormSelection ();
  946. break;
  947. case kpSelection::Text:
  948. m_mainWindow->slotToolText ();
  949. break;
  950. default:
  951. break;
  952. }
  953. }
  954. if (m_selection)
  955. {
  956. // TODO: Emitting this, before setting the new selection, is bogus
  957. // since it would redraw the old selection.
  958. //
  959. // Luckily, this doesn't matter thanks to the
  960. // kpViewManager::setQueueUpdates() call above.
  961. if (m_selection->pixmap ())
  962. slotContentsChanged (m_selection->boundingRect ());
  963. else
  964. // TODO: Should emit contentsChanged() instead?
  965. // I don't think it matters since contentsChanged() is
  966. // connected to updateViews() anyway (see
  967. // kpMainWindow::setDocument ()).
  968. vm->updateViews (m_selection->boundingRect ());
  969. delete m_selection;
  970. }
  971. m_selection = new kpSelection (selection);
  972. // TODO: this coupling is bad, careless and lazy
  973. if (m_mainWindow)
  974. {
  975. if (!m_selection->isText ())
  976. {
  977. if (m_selection->transparency () != m_mainWindow->selectionTransparency ())
  978. {
  979. kdDebug () << "kpDocument::setSelection() sel's transparency differs "
  980. "from mainWindow's transparency - setting mainWindow's transparency "
  981. "to sel"
  982. << endl;
  983. kdDebug () << "\tisOpaque: sel=" << m_selection->transparency ().isOpaque ()
  984. << " mainWindow=" << m_mainWindow->selectionTransparency ().isOpaque ()
  985. << endl;
  986. m_mainWindow->setSelectionTransparency (m_selection->transparency ());
  987. }
  988. }
  989. else
  990. {
  991. if (m_selection->textStyle () != m_mainWindow->textStyle ())
  992. {
  993. kdDebug () << "kpDocument::setSelection() sel's textStyle differs "
  994. "from mainWindow's textStyle - setting mainWindow's textStyle "
  995. "to sel"
  996. << endl;
  997. m_mainWindow->setTextStyle (m_selection->textStyle ());
  998. }
  999. }
  1000. }
  1001. updateToolsSingleKeyTriggersEnabled ();
  1002. #if DEBUG_KP_DOCUMENT && 0
  1003. kdDebug () << "\tcheck sel " << (int *) m_selection
  1004. << " boundingRect=" << m_selection->boundingRect ()
  1005. << endl;
  1006. #endif
  1007. if (m_selection->pixmap ())
  1008. slotContentsChanged (m_selection->boundingRect ());
  1009. else
  1010. // TODO: Should emit contentsChanged() instead?
  1011. // I don't think it matters since contentsChanged() is
  1012. // connected to updateViews() anyway (see
  1013. // kpMainWindow::setDocument ()).
  1014. vm->updateViews (m_selection->boundingRect ());
  1015. // There's no need to disconnect() the old selection since we:
  1016. //
  1017. // 1. Connect our _copy_ of the given selection.
  1018. // 2. We delete our copy when setSelection() is called again.
  1019. //
  1020. // See code above for both.
  1021. connect (m_selection, TQT_SIGNAL (changed (const TQRect &)),
  1022. this, TQT_SLOT (slotContentsChanged (const TQRect &)));
  1023. if (!hadSelection)
  1024. emit selectionEnabled (true);
  1025. if (isTextChanged)
  1026. emit selectionIsTextChanged (selection.type () == kpSelection::Text);
  1027. if (vm)
  1028. vm->restoreQueueUpdates ();
  1029. }
  1030. // public
  1031. TQPixmap kpDocument::getSelectedPixmap (const TQBitmap &maskBitmap_) const
  1032. {
  1033. kpSelection *sel = selection ();
  1034. // must have a selection region
  1035. if (!sel)
  1036. {
  1037. kdError () << "kpDocument::getSelectedPixmap() no sel region" << endl;
  1038. return TQPixmap ();
  1039. }
  1040. // easy if we already have it :)
  1041. if (sel->pixmap ())
  1042. return *sel->pixmap ();
  1043. const TQRect boundingRect = sel->boundingRect ();
  1044. if (!boundingRect.isValid ())
  1045. {
  1046. kdError () << "kpDocument::getSelectedPixmap() boundingRect invalid" << endl;
  1047. return TQPixmap ();
  1048. }
  1049. TQBitmap maskBitmap = maskBitmap_;
  1050. if (maskBitmap.isNull () &&
  1051. !sel->isRectangular ())
  1052. {
  1053. maskBitmap = sel->maskForOwnType ();
  1054. if (maskBitmap.isNull ())
  1055. {
  1056. kdError () << "kpDocument::getSelectedPixmap() could not get mask" << endl;
  1057. return TQPixmap ();
  1058. }
  1059. }
  1060. TQPixmap selPixmap = getPixmapAt (boundingRect);
  1061. if (!maskBitmap.isNull ())
  1062. {
  1063. // Src Dest = Result
  1064. // -----------------
  1065. // 0 0 0
  1066. // 0 1 0
  1067. // 1 0 0
  1068. // 1 1 1
  1069. TQBitmap selMaskBitmap = kpPixmapFX::getNonNullMask (selPixmap);
  1070. bitBlt (&selMaskBitmap,
  1071. TQPoint (0, 0),
  1072. &maskBitmap,
  1073. TQRect (0, 0, maskBitmap.width (), maskBitmap.height ()),
  1074. TQt::AndROP);
  1075. selPixmap.setMask (selMaskBitmap);
  1076. }
  1077. return selPixmap;
  1078. }
  1079. // public
  1080. bool kpDocument::selectionPullFromDocument (const kpColor &backgroundColor)
  1081. {
  1082. kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
  1083. kpSelection *sel = selection ();
  1084. // must have a selection region
  1085. if (!sel)
  1086. {
  1087. kdError () << "kpDocument::selectionPullFromDocument() no sel region" << endl;
  1088. return false;
  1089. }
  1090. // should not already have a pixmap
  1091. if (sel->pixmap ())
  1092. {
  1093. kdError () << "kpDocument::selectionPullFromDocument() already has pixmap" << endl;
  1094. return false;
  1095. }
  1096. const TQRect boundingRect = sel->boundingRect ();
  1097. if (!boundingRect.isValid ())
  1098. {
  1099. kdError () << "kpDocument::selectionPullFromDocument() boundingRect invalid" << endl;
  1100. return false;
  1101. }
  1102. //
  1103. // Figure out mask for non-rectangular selections
  1104. //
  1105. TQBitmap maskBitmap = sel->maskForOwnType (true/*return null bitmap for rectangular*/);
  1106. //
  1107. // Get selection pixmap from document
  1108. //
  1109. TQPixmap selPixmap = getSelectedPixmap (maskBitmap);
  1110. if (vm)
  1111. vm->setQueueUpdates ();
  1112. sel->setPixmap (selPixmap);
  1113. //
  1114. // Fill opaque bits of the hole in the document
  1115. //
  1116. // TODO: this assumes backgroundColor == sel->transparency ().transparentColor()
  1117. const TQPixmap selTransparentPixmap = sel->transparentPixmap ();
  1118. if (backgroundColor.isOpaque ())
  1119. {
  1120. TQPixmap erasePixmap (boundingRect.width (), boundingRect.height ());
  1121. erasePixmap.fill (backgroundColor.toTQColor ());
  1122. if (selTransparentPixmap.mask ())
  1123. erasePixmap.setMask (*selTransparentPixmap.mask ());
  1124. paintPixmapAt (erasePixmap, boundingRect.topLeft ());
  1125. }
  1126. else
  1127. {
  1128. kpPixmapFX::paintMaskTransparentWithBrush (m_pixmap,
  1129. boundingRect.topLeft (),
  1130. kpPixmapFX::getNonNullMask (selTransparentPixmap));
  1131. slotContentsChanged (boundingRect);
  1132. }
  1133. if (vm)
  1134. vm->restoreQueueUpdates ();
  1135. return true;
  1136. }
  1137. // public
  1138. bool kpDocument::selectionDelete ()
  1139. {
  1140. kpSelection *sel = selection ();
  1141. if (!sel)
  1142. return false;
  1143. const TQRect boundingRect = sel->boundingRect ();
  1144. if (!boundingRect.isValid ())
  1145. return false;
  1146. bool selectionHadPixmap = m_selection ? (bool) m_selection->pixmap () : false;
  1147. delete m_selection;
  1148. m_selection = 0;
  1149. // HACK to prevent document from being modified when
  1150. // user cancels dragging out a new selection
  1151. if (selectionHadPixmap)
  1152. slotContentsChanged (boundingRect);
  1153. else
  1154. emit contentsChanged (boundingRect);
  1155. emit selectionEnabled (false);
  1156. updateToolsSingleKeyTriggersEnabled ();
  1157. return true;
  1158. }
  1159. // public
  1160. bool kpDocument::selectionCopyOntoDocument (bool useTransparentPixmap)
  1161. {
  1162. kpSelection *sel = selection ();
  1163. // must have a pixmap already
  1164. if (!sel)
  1165. return false;
  1166. // hasn't actually been lifted yet
  1167. if (!sel->pixmap ())
  1168. return true;
  1169. const TQRect boundingRect = sel->boundingRect ();
  1170. if (!boundingRect.isValid ())
  1171. return false;
  1172. if (!sel->isText ())
  1173. {
  1174. // We can't use kpSelection::paint() since that always uses the
  1175. // transparent pixmap.
  1176. paintPixmapAt (useTransparentPixmap ? sel->transparentPixmap () : sel->opaquePixmap (),
  1177. boundingRect.topLeft ());
  1178. }
  1179. else
  1180. {
  1181. // (for antialiasing with background)
  1182. sel->paint (m_pixmap, rect ());
  1183. }
  1184. slotContentsChanged (boundingRect);
  1185. return true;
  1186. }
  1187. // public
  1188. bool kpDocument::selectionPushOntoDocument (bool useTransparentPixmap)
  1189. {
  1190. return (selectionCopyOntoDocument (useTransparentPixmap) && selectionDelete ());
  1191. }
  1192. // public
  1193. TQPixmap kpDocument::pixmapWithSelection () const
  1194. {
  1195. #if DEBUG_KP_DOCUMENT && 1
  1196. kdDebug () << "kpDocument::pixmapWithSelection()" << endl;
  1197. #endif
  1198. // Have floating selection?
  1199. if (m_selection && m_selection->pixmap ())
  1200. {
  1201. #if DEBUG_KP_DOCUMENT && 1
  1202. kdDebug () << "\tselection @ " << m_selection->boundingRect () << endl;
  1203. #endif
  1204. TQPixmap output = *m_pixmap;
  1205. m_selection->paint (&output, rect ());
  1206. return output;
  1207. }
  1208. else
  1209. {
  1210. #if DEBUG_KP_DOCUMENT && 1
  1211. kdDebug () << "\tno selection" << endl;
  1212. #endif
  1213. return *m_pixmap;
  1214. }
  1215. }
  1216. /*
  1217. * Transformations
  1218. */
  1219. void kpDocument::fill (const kpColor &color)
  1220. {
  1221. #if DEBUG_KP_DOCUMENT
  1222. kdDebug () << "kpDocument::fill ()" << endl;
  1223. #endif
  1224. kpPixmapFX::fill (m_pixmap, color);
  1225. slotContentsChanged (m_pixmap->rect ());
  1226. }
  1227. void kpDocument::resize (int w, int h, const kpColor &backgroundColor, bool fillNewAreas)
  1228. {
  1229. #if DEBUG_KP_DOCUMENT
  1230. kdDebug () << "kpDocument::resize (" << w << "," << h << "," << fillNewAreas << ")" << endl;
  1231. #endif
  1232. m_oldWidth = width (), m_oldHeight = height ();
  1233. #if DEBUG_KP_DOCUMENT && 1
  1234. kdDebug () << "\toldWidth=" << m_oldWidth
  1235. << " oldHeight=" << m_oldHeight
  1236. << endl;
  1237. #endif
  1238. if (w == m_oldWidth && h == m_oldHeight)
  1239. return;
  1240. kpPixmapFX::resize (m_pixmap, w, h, backgroundColor, fillNewAreas);
  1241. slotSizeChanged (width (), height ());
  1242. }
  1243. /*
  1244. * Slots
  1245. */
  1246. void kpDocument::slotContentsChanged (const TQRect &rect)
  1247. {
  1248. setModified ();
  1249. emit contentsChanged (rect);
  1250. }
  1251. void kpDocument::slotSizeChanged (int newWidth, int newHeight)
  1252. {
  1253. setModified ();
  1254. emit sizeChanged (newWidth, newHeight);
  1255. emit sizeChanged (TQSize (newWidth, newHeight));
  1256. }
  1257. void kpDocument::slotSizeChanged (const TQSize &newSize)
  1258. {
  1259. slotSizeChanged (newSize.width (), newSize.height ());
  1260. }
  1261. #include <kpdocument.moc>