TDE graphics utilities
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kpmainwindow.cpp 33KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  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. #include <kpmainwindow.h>
  24. #include <kpmainwindow_p.h>
  25. #include <tqdragobject.h>
  26. #include <tqpainter.h>
  27. #include <tqtimer.h>
  28. #include <kactionclasses.h>
  29. #include <kapplication.h>
  30. #include <kconfig.h>
  31. #include <kdebug.h>
  32. #include <klocale.h>
  33. #include <kmessagebox.h>
  34. #include <kurldrag.h>
  35. #include <kpcolortoolbar.h>
  36. #include <kpcommandhistory.h>
  37. #include <kpdefs.h>
  38. #include <kpdocument.h>
  39. #include <kppixmapfx.h>
  40. #include <kpselection.h>
  41. #include <kpselectiondrag.h>
  42. #include <kpsinglekeytriggersaction.h>
  43. #include <kpthumbnail.h>
  44. #include <kptool.h>
  45. #include <kptooltoolbar.h>
  46. #include <kpviewmanager.h>
  47. #include <kpviewscrollablecontainer.h>
  48. #include <kpwidgetmapper.h>
  49. #include <kpzoomedthumbnailview.h>
  50. #include <kpzoomedview.h>
  51. #if DEBUG_KP_MAIN_WINDOW
  52. #include <tqdatetime.h>
  53. #endif
  54. kpMainWindow::kpMainWindow ()
  55. : KMainWindow (0/*parent*/, "mainWindow"),
  56. m_isFullyConstructed (false)
  57. {
  58. init ();
  59. open (KURL (), true/*create an empty doc*/);
  60. m_isFullyConstructed = true;
  61. }
  62. kpMainWindow::kpMainWindow (const KURL &url)
  63. : KMainWindow (0/*parent*/, "mainWindow"),
  64. m_isFullyConstructed (false)
  65. {
  66. init ();
  67. open (url, true/*create an empty doc with the same url if url !exist*/);
  68. m_isFullyConstructed = true;
  69. }
  70. kpMainWindow::kpMainWindow (kpDocument *newDoc)
  71. : KMainWindow (0/*parent*/, "mainWindow"),
  72. m_isFullyConstructed (false)
  73. {
  74. init ();
  75. setDocument (newDoc);
  76. m_isFullyConstructed = true;
  77. }
  78. // public
  79. double kpMainWindow::configColorSimilarity () const
  80. {
  81. return m_configColorSimilarity;
  82. }
  83. // public
  84. void kpMainWindow::configSetColorSimilarity (double val)
  85. {
  86. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
  87. TDEConfigBase *cfg = cfgGroupSaver.config ();
  88. cfg->writeEntry (kpSettingColorSimilarity, m_configColorSimilarity = val);
  89. cfg->sync ();
  90. }
  91. // private
  92. void kpMainWindow::readGeneralSettings ()
  93. {
  94. #if DEBUG_KP_MAIN_WINDOW
  95. kdDebug () << "\tkpMainWindow(" << name () << ")::readGeneralSettings()" << endl;
  96. #endif
  97. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
  98. TDEConfigBase *cfg = cfgGroupSaver.config ();
  99. m_configFirstTime = cfg->readBoolEntry (kpSettingFirstTime, true);
  100. m_configShowGrid = cfg->readBoolEntry (kpSettingShowGrid, false);
  101. m_configShowPath = cfg->readBoolEntry (kpSettingShowPath, false);
  102. m_configColorSimilarity = cfg->readDoubleNumEntry (kpSettingColorSimilarity, 0);
  103. d->m_moreEffectsDialogLastEffect = cfg->readNumEntry (kpSettingMoreEffectsLastEffect);
  104. d->m_resizeScaleDialogLastKeepAspect = cfg->readBoolEntry (kpSettingResizeScaleLastKeepAspect, false);
  105. #if DEBUG_KP_MAIN_WINDOW
  106. kdDebug () << "\t\tGeneral Settings: firstTime=" << m_configFirstTime
  107. << " showGrid=" << m_configShowGrid
  108. << " showPath=" << m_configShowPath
  109. << " colorSimilarity=" << m_configColorSimilarity
  110. << " moreEffectsDialogLastEffect=" << d->m_moreEffectsDialogLastEffect
  111. << " resizeScaleDialogLastKeepAspect=" << d->m_resizeScaleDialogLastKeepAspect
  112. << endl;
  113. #endif
  114. }
  115. // private
  116. void kpMainWindow::readThumbnailSettings ()
  117. {
  118. #if DEBUG_KP_MAIN_WINDOW
  119. kdDebug () << "\tkpMainWindow(" << name () << ")::readThumbnailSettings()" << endl;
  120. #endif
  121. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
  122. TDEConfigBase *cfg = cfgGroupSaver.config ();
  123. m_configThumbnailShown = cfg->readBoolEntry (kpSettingThumbnailShown, false);
  124. m_configThumbnailGeometry = cfg->readRectEntry (kpSettingThumbnailGeometry);
  125. m_configZoomedThumbnail = cfg->readBoolEntry (kpSettingThumbnailZoomed, true);
  126. d->m_configThumbnailShowRectangle = cfg->readBoolEntry (kpSettingThumbnailShowRectangle, true);
  127. #if DEBUG_KP_MAIN_WINDOW
  128. kdDebug () << "\t\tThumbnail Settings: shown=" << m_configThumbnailShown
  129. << " geometry=" << m_configThumbnailGeometry
  130. << " zoomed=" << m_configZoomedThumbnail
  131. << " showRectangle=" << d->m_configThumbnailShowRectangle
  132. << endl;
  133. #endif
  134. }
  135. // private
  136. void kpMainWindow::init ()
  137. {
  138. #if DEBUG_KP_MAIN_WINDOW
  139. kdDebug () << "kpMainWindow(" << name () << ")::init()" << endl;
  140. TQTime totalTime; totalTime.start ();
  141. TQTime time; time.start ();
  142. #endif
  143. d = new kpMainWindowPrivate;
  144. m_scrollView = 0;
  145. m_mainView = 0;
  146. m_thumbnail = 0;
  147. m_thumbnailView = 0;
  148. m_document = 0;
  149. m_viewManager = 0;
  150. m_colorToolBar = 0;
  151. m_toolToolBar = 0;
  152. m_commandHistory = 0;
  153. m_statusBarCreated = false;
  154. m_settingSelectionTransparency = 0;
  155. m_settingTextStyle = 0;
  156. m_docResizeToBeCompleted = false;
  157. //
  158. // set mainwindow properties
  159. //
  160. setMinimumSize (320, 260);
  161. setAcceptDrops (true);
  162. #if DEBUG_KP_MAIN_WINDOW
  163. kdDebug () << "\tTIME: little init = " << time.restart () << "msec" << endl;
  164. #endif
  165. //
  166. // read config
  167. //
  168. // TDEConfig::readEntry() does not actually reread from disk, hence doesn't
  169. // realise what other processes have done e.g. Settings / Show Path
  170. kapp->config ()->reparseConfiguration ();
  171. #if DEBUG_KP_MAIN_WINDOW
  172. kdDebug () << "\tTIME: reparseConfig = " << time.restart () << "msec" << endl;
  173. #endif
  174. readGeneralSettings ();
  175. #if DEBUG_KP_MAIN_WINDOW
  176. kdDebug () << "\tTIME: readGeneralSettings = " << time.restart () << "msec" << endl;
  177. #endif
  178. readThumbnailSettings ();
  179. #if DEBUG_KP_MAIN_WINDOW
  180. kdDebug () << "\tTIME: readThumbnailSettings = " << time.restart () << "msec" << endl;
  181. #endif
  182. //
  183. // create GUI
  184. //
  185. setupActions ();
  186. #if DEBUG_KP_MAIN_WINDOW
  187. kdDebug () << "\tTIME: setupActions = " << time.restart () << "msec" << endl;
  188. #endif
  189. createStatusBar ();
  190. #if DEBUG_KP_MAIN_WINDOW
  191. kdDebug () << "\tTIME: createStatusBar = " << time.restart () << "msec" << endl;
  192. #endif
  193. createGUI ();
  194. #if DEBUG_KP_MAIN_WINDOW
  195. kdDebug () << "\tTIME: createGUI = " << time.restart () << "msec" << endl;
  196. #endif
  197. //
  198. // create more GUI
  199. //
  200. m_colorToolBar = new kpColorToolBar (i18n ("Color Box"), this, "Color Box");
  201. #if DEBUG_KP_MAIN_WINDOW
  202. kdDebug () << "\tTIME: new kpColorToolBar = " << time.restart () << "msec" << endl;
  203. #endif
  204. createToolBox ();
  205. #if DEBUG_KP_MAIN_WINDOW
  206. kdDebug () << "\tTIME: createToolBox = " << time.restart () << "msec" << endl;
  207. #endif
  208. m_scrollView = new kpViewScrollableContainer (this, "scrollView");
  209. connect (m_scrollView, TQT_SIGNAL (beganDocResize ()),
  210. this, TQT_SLOT (slotBeganDocResize ()));
  211. connect (m_scrollView, TQT_SIGNAL (continuedDocResize (const TQSize &)),
  212. this, TQT_SLOT (slotContinuedDocResize (const TQSize &)));
  213. connect (m_scrollView, TQT_SIGNAL (cancelledDocResize ()),
  214. this, TQT_SLOT (slotCancelledDocResize ()));
  215. connect (m_scrollView, TQT_SIGNAL (endedDocResize (const TQSize &)),
  216. this, TQT_SLOT (slotEndedDocResize (const TQSize &)));
  217. connect (m_scrollView, TQT_SIGNAL (statusMessageChanged (const TQString &)),
  218. this, TQT_SLOT (slotDocResizeMessageChanged (const TQString &)));
  219. connect (m_scrollView, TQT_SIGNAL (contentsMoving (int, int)),
  220. this, TQT_SLOT (slotScrollViewAboutToScroll ()));
  221. setCentralWidget (m_scrollView);
  222. m_scrollView->show ();
  223. #if DEBUG_KP_MAIN_WINDOW
  224. kdDebug () << "\tTIME: m_scrollView = " << time.restart () << "msec" << endl;
  225. #endif
  226. //
  227. // set initial pos/size of GUI
  228. //
  229. setAutoSaveSettings ();
  230. // Put our non-XMLGUI toolbars in a sane place, the first time around
  231. // (have to do this _after_ setAutoSaveSettings as that applies default
  232. // (i.e. random) settings to the toolbars)
  233. if (m_configFirstTime)
  234. {
  235. #if DEBUG_KP_MAIN_WINDOW
  236. kdDebug () << "\tfirstTime: positioning toolbars" << endl;
  237. #endif
  238. m_toolToolBar->setBarPos (KToolBar::Left);
  239. m_colorToolBar->setBarPos (KToolBar::Bottom);
  240. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
  241. TDEConfigBase *cfg = cfgGroupSaver.config ();
  242. cfg->writeEntry (kpSettingFirstTime, m_configFirstTime = false);
  243. cfg->sync ();
  244. }
  245. #if DEBUG_KP_MAIN_WINDOW
  246. kdDebug () << "\tall done in " << totalTime.elapsed () << "msec" << endl;
  247. #endif
  248. }
  249. // private virtual [base KMainWindow]
  250. void kpMainWindow::readProperties (TDEConfig *cfg)
  251. {
  252. #if DEBUG_KP_MAIN_WINDOW
  253. kdDebug () << "kpMainWindow<" << this << ">::readProperties()" << endl;
  254. #endif
  255. // No document at all?
  256. if (!cfg->hasKey (kpSessionSettingDocumentUrl))
  257. {
  258. #if DEBUG_KP_MAIN_WINDOW
  259. kdDebug () << "\tno url - no document" << endl;
  260. #endif
  261. setDocument (0);
  262. }
  263. // Have a document.
  264. else
  265. {
  266. const KURL url (cfg->readEntry (kpSessionSettingDocumentUrl));
  267. #if DEBUG_KP_MAIN_WINDOW
  268. kdDebug () << "\turl=" << url << endl;
  269. #endif
  270. const TQSize notFromURLDocSize =
  271. cfg->readSizeEntry (kpSessionSettingNotFromUrlDocumentSize);
  272. // Is from URL?
  273. if (notFromURLDocSize.isEmpty ())
  274. {
  275. // If this fails, the empty document that kpMainWindow::kpMainWindow()
  276. // created is left untouched.
  277. openInternal (url, defaultDocSize (),
  278. false/*show error message if url !exist*/);
  279. }
  280. // Not from URL?
  281. else
  282. {
  283. #if DEBUG_KP_MAIN_WINDOW
  284. kdDebug () << "\tnot from url; doc size=" << notFromURLDocSize << endl;
  285. #endif
  286. // Either we have an empty URL or we have a "kolourpaint doesnotexist.png"
  287. // URL. Regarding the latter case, if a file now actually exists at that
  288. // URL, we do open it - ignoring notFromURLDocSize - to avoid putting
  289. // the user in a situation where he might accidentally overwrite an
  290. // existing file.
  291. openInternal (url, notFromURLDocSize,
  292. true/*create an empty doc with the same url if url !exist*/);
  293. }
  294. }
  295. }
  296. // private virtual [base KMainWindow]
  297. // WARNING: KMainWindow API Doc says "No user interaction is allowed
  298. // in this function!"
  299. void kpMainWindow::saveProperties (TDEConfig *cfg)
  300. {
  301. #if DEBUG_KP_MAIN_WINDOW
  302. kdDebug () << "kpMainWindow<" << this << ">::saveProperties()" << endl;
  303. #endif
  304. // No document at all?
  305. if (!m_document)
  306. {
  307. #if DEBUG_KP_MAIN_WINDOW
  308. kdDebug () << "\tno url - no document" << endl;
  309. #endif
  310. }
  311. // Have a document.
  312. else
  313. {
  314. // Save URL in all cases:
  315. //
  316. // a) m_document->isFromURL()
  317. // b) !m_document->isFromURL() [save size in this case]
  318. // i) No URL
  319. // ii) URL (from "kolourpaint doesnotexist.png")
  320. const KURL url = m_document->url ();
  321. #if DEBUG_KP_MAIN_WINDOW
  322. kdDebug () << "\turl=" << url << endl;
  323. #endif
  324. cfg->writeEntry (kpSessionSettingDocumentUrl, url.url ());
  325. // Not from URL e.g. "kolourpaint doesnotexist.png"?
  326. //
  327. // Note that "kolourpaint doesexist.png" is considered to be from
  328. // a URL even if it was deleted in the background (hence the
  329. // "false" arg to isFromURL()). This is because the user expects
  330. // it to be from a URL, so when we session restore, we pop up a
  331. // "cannot find file" dialog, instead of silently creating a new,
  332. // blank document.
  333. if (!m_document->isFromURL (false/*don't bother checking exists*/))
  334. {
  335. // If we don't have a URL either:
  336. //
  337. // a) it was not modified - so we can use either width() or
  338. // constructorWidth() (they'll be equal).
  339. // b) the changes were discarded so we use the initial width,
  340. // constructorWidth().
  341. //
  342. // Similarly for height() and constructorHeight().
  343. const TQSize docSize (m_document->constructorWidth (),
  344. m_document->constructorHeight ());
  345. #if DEBUG_KP_MAIN_WINDOW
  346. kdDebug () << "\tnot from url; doc size=" << docSize << endl;
  347. #endif
  348. cfg->writeEntry (kpSessionSettingNotFromUrlDocumentSize, docSize);
  349. }
  350. // Local session save i.e. queryClose() was not called beforehand
  351. // (see TQApplication::saveState())?
  352. #if 0
  353. if (m_document->isModified ())
  354. {
  355. // TODO: Implement by saving the current image to a persistent file.
  356. // We do this instead of saving/mutating the backing image file
  357. // as no one expects a file save on a session save without a
  358. // "do you want to save" dialog first.
  359. //
  360. // I don't think any KDE application implements local session saving.
  361. //
  362. // --- The below code does not compile but shows you want to do ---
  363. // Create unique name for the document in this main window.
  364. const KURL tempURL = homeDir +
  365. "kolourpaint session " + sessionID +
  366. mainWindowPtrToString + ".png";
  367. // TODO: Use lossless PNG saving options.
  368. kpDocumentSaveOptions pngSaveOptions;
  369. if (kpDocument::savePixmapToFile (m_document->pixmapWithSelection (),
  370. tempURL,
  371. pngSaveOptions, *m_document->metaInfo (),
  372. false/*no overwrite prompt*/,
  373. false/*no lossy prompt*/,
  374. this))
  375. {
  376. // readProperties() will still open kpSessionSettingDocumentUrl
  377. // (as that's the expected URL) and will then add commands to:
  378. //
  379. // 1. Resize the document to the size of image at
  380. // kpSessionSettingDocumentUnsavedContentsUrl, if the sizes
  381. // differ.
  382. // 2. Paste the kpSessionSettingDocumentUnsavedContentsUrl image
  383. // (setting the main window's selection mode to opaque beforehand).
  384. //
  385. // It will then delete the file at
  386. // kpSessionSettingDocumentUnsavedContentsUrl.
  387. cfg->writeEntry (kpSessionSettingDocumentUnsavedContentsUrl,
  388. tempURL.url ());
  389. }
  390. else
  391. {
  392. // Not much we can do - we aren't allowed to throw up a dialog.
  393. }
  394. }
  395. #endif
  396. }
  397. }
  398. kpMainWindow::~kpMainWindow ()
  399. {
  400. m_isFullyConstructed = false;
  401. // delete document & views
  402. setDocument (0);
  403. delete m_commandHistory; m_commandHistory = 0;
  404. delete m_scrollView; m_scrollView = 0;
  405. delete d; d = 0;
  406. }
  407. // public
  408. kpDocument *kpMainWindow::document () const
  409. {
  410. return m_document;
  411. }
  412. // public
  413. kpViewManager *kpMainWindow::viewManager () const
  414. {
  415. return m_viewManager;
  416. }
  417. // public
  418. kpColorToolBar *kpMainWindow::colorToolBar () const
  419. {
  420. return m_colorToolBar;
  421. }
  422. // public
  423. kpToolToolBar *kpMainWindow::toolToolBar () const
  424. {
  425. return m_toolToolBar;
  426. }
  427. // public
  428. kpCommandHistory *kpMainWindow::commandHistory () const
  429. {
  430. return m_commandHistory;
  431. }
  432. // private
  433. void kpMainWindow::setupActions ()
  434. {
  435. setupFileMenuActions ();
  436. setupEditMenuActions ();
  437. setupViewMenuActions ();
  438. setupImageMenuActions ();
  439. setupSettingsMenuActions ();
  440. setupHelpMenuActions ();
  441. setupTextToolBarActions ();
  442. setupToolActions ();
  443. }
  444. // private
  445. void kpMainWindow::enableDocumentActions (bool enable)
  446. {
  447. enableFileMenuDocumentActions (enable);
  448. enableEditMenuDocumentActions (enable);
  449. enableViewMenuDocumentActions (enable);
  450. enableImageMenuDocumentActions (enable);
  451. enableSettingsMenuDocumentActions (enable);
  452. enableHelpMenuDocumentActions (enable);
  453. }
  454. // public
  455. bool kpMainWindow::actionsSingleKeyTriggersEnabled () const
  456. {
  457. #if DEBUG_KP_MAIN_WINDOW
  458. kdDebug () << "kpMainWindow::actionsSingleKeyTriggersEnabled()" << endl;
  459. TQTime timer; timer.start ();
  460. #endif
  461. if (m_toolToolBar)
  462. {
  463. #if DEBUG_KP_MAIN_WINDOW
  464. kdDebug () << "\ttime=" << timer.restart () << endl;
  465. #endif
  466. return m_toolToolBar->toolsSingleKeyTriggersEnabled ();
  467. }
  468. return (m_actionPrevToolOptionGroup1->singleKeyTriggersEnabled () ||
  469. m_actionNextToolOptionGroup1->singleKeyTriggersEnabled () ||
  470. m_actionPrevToolOptionGroup2->singleKeyTriggersEnabled () ||
  471. m_actionNextToolOptionGroup2->singleKeyTriggersEnabled ());
  472. }
  473. // public
  474. void kpMainWindow::enableActionsSingleKeyTriggers (bool enable)
  475. {
  476. #if DEBUG_KP_MAIN_WINDOW
  477. kdDebug () << "kpMainWindow::enableActionsSingleKeyTriggers("
  478. << enable << ")" << endl;
  479. TQTime timer; timer.start ();
  480. #endif
  481. if (m_toolToolBar)
  482. m_toolToolBar->enableToolsSingleKeyTriggers (enable);
  483. m_actionPrevToolOptionGroup1->enableSingleKeyTriggers (enable);
  484. m_actionNextToolOptionGroup1->enableSingleKeyTriggers (enable);
  485. m_actionPrevToolOptionGroup2->enableSingleKeyTriggers (enable);
  486. m_actionNextToolOptionGroup2->enableSingleKeyTriggers (enable);
  487. #if DEBUG_KP_MAIN_WINDOW
  488. kdDebug () << "\ttime=" << timer.restart () << endl;
  489. #endif
  490. }
  491. // private
  492. void kpMainWindow::setDocument (kpDocument *newDoc)
  493. {
  494. #if DEBUG_KP_MAIN_WINDOW
  495. kdDebug () << "kpMainWindow::setDocument (" << newDoc << ")" << endl;
  496. #endif
  497. // is it a close operation?
  498. if (!newDoc)
  499. {
  500. #if DEBUG_KP_MAIN_WINDOW
  501. kdDebug () << "\tdisabling actions" << endl;
  502. #endif
  503. // sync with the bit marked "sync" below
  504. if (m_colorToolBar)
  505. m_colorToolBar->setEnabled (false);
  506. else
  507. {
  508. kdError () << "kpMainWindow::setDocument() without colorToolBar"
  509. << endl;
  510. }
  511. enableTextToolBarActions (false);
  512. }
  513. // Always disable the tools.
  514. // If we decide to open a new document/mainView we want
  515. // kpTool::begin() to be called again e.g. in case it sets the cursor.
  516. // kpViewManager won't do this because we nuke it to avoid stale state.
  517. enableToolsDocumentActions (false);
  518. if (!newDoc)
  519. {
  520. enableDocumentActions (false);
  521. }
  522. #if DEBUG_KP_MAIN_WINDOW
  523. kdDebug () << "\tdestroying views" << endl;
  524. #endif
  525. delete m_mainView; m_mainView = 0;
  526. slotDestroyThumbnail ();
  527. #if DEBUG_KP_MAIN_WINDOW
  528. kdDebug () << "\tdestroying viewManager" << endl;
  529. #endif
  530. // viewManager will die and so will the selection
  531. m_actionCopy->setEnabled (false);
  532. m_actionCut->setEnabled (false);
  533. m_actionDelete->setEnabled (false);
  534. m_actionDeselect->setEnabled (false);
  535. m_actionCopyToFile->setEnabled (false);
  536. delete m_viewManager; m_viewManager = 0;
  537. #if DEBUG_KP_MAIN_WINDOW
  538. kdDebug () << "\tdestroying document" << endl;
  539. kdDebug () << "\t\tm_document=" << m_document << endl;
  540. #endif
  541. // destroy current document
  542. delete m_document;
  543. m_document = newDoc;
  544. if (!m_lastCopyToURL.isEmpty ())
  545. m_lastCopyToURL.setFileName (TQString());
  546. m_copyToFirstTime = true;
  547. if (!m_lastExportURL.isEmpty ())
  548. m_lastExportURL.setFileName (TQString());
  549. m_exportFirstTime = true;
  550. // not a close operation?
  551. if (m_document)
  552. {
  553. if (m_document->mainWindow () != this)
  554. {
  555. #if DEBUG_KP_MAIN_WINDOW
  556. kdDebug () << "\tchanging doc's mainWindow from "
  557. << m_document->mainWindow ()
  558. << " to this="
  559. << this
  560. << endl;
  561. #endif
  562. m_document->setMainWindow (this);
  563. }
  564. #if DEBUG_KP_MAIN_WINDOW
  565. kdDebug () <<"\tcreating viewManager" << endl;
  566. #endif
  567. m_viewManager = new kpViewManager (this);
  568. #if DEBUG_KP_MAIN_WINDOW
  569. kdDebug () << "\tcreating views" << endl;
  570. #endif
  571. m_mainView = new kpZoomedView (m_document, m_toolToolBar, m_viewManager,
  572. 0/*buddyView*/,
  573. m_scrollView,
  574. m_scrollView->viewport (), "mainView");
  575. if (m_scrollView)
  576. {
  577. m_scrollView->addChild (m_mainView);
  578. }
  579. else
  580. kdError () << "kpMainWindow::setDocument() without scrollView" << endl;
  581. m_viewManager->registerView (m_mainView);
  582. m_mainView->show ();
  583. #if DEBUG_KP_MAIN_WINDOW
  584. kdDebug () << "\thooking up document signals" << endl;
  585. #endif
  586. // Copy/Cut/Deselect/Delete
  587. connect (m_document, TQT_SIGNAL (selectionEnabled (bool)),
  588. m_actionCut, TQT_SLOT (setEnabled (bool)));
  589. connect (m_document, TQT_SIGNAL (selectionEnabled (bool)),
  590. m_actionCopy, TQT_SLOT (setEnabled (bool)));
  591. connect (m_document, TQT_SIGNAL (selectionEnabled (bool)),
  592. m_actionDelete, TQT_SLOT (setEnabled (bool)));
  593. connect (m_document, TQT_SIGNAL (selectionEnabled (bool)),
  594. m_actionDeselect, TQT_SLOT (setEnabled (bool)));
  595. connect (m_document, TQT_SIGNAL (selectionEnabled (bool)),
  596. m_actionCopyToFile, TQT_SLOT (setEnabled (bool)));
  597. // this code won't actually enable any actions at this stage
  598. // (fresh document) but better safe than sorry
  599. m_actionCopy->setEnabled (m_document->selection ());
  600. m_actionCut->setEnabled (m_document->selection ());
  601. m_actionDeselect->setEnabled (m_document->selection ());
  602. m_actionDelete->setEnabled (m_document->selection ());
  603. m_actionCopyToFile->setEnabled (m_document->selection ());
  604. connect (m_document, TQT_SIGNAL (selectionEnabled (bool)),
  605. this, TQT_SLOT (slotImageMenuUpdateDueToSelection ()));
  606. connect (m_document, TQT_SIGNAL (selectionIsTextChanged (bool)),
  607. this, TQT_SLOT (slotImageMenuUpdateDueToSelection ()));
  608. // Status bar
  609. connect (m_document, TQT_SIGNAL (documentOpened ()),
  610. this, TQT_SLOT (recalculateStatusBar ()));
  611. connect (m_document, TQT_SIGNAL (sizeChanged (const TQSize &)),
  612. this, TQT_SLOT (setStatusBarDocSize (const TQSize &)));
  613. // Caption (url, modified)
  614. connect (m_document, TQT_SIGNAL (documentModified ()),
  615. this, TQT_SLOT (slotUpdateCaption ()));
  616. connect (m_document, TQT_SIGNAL (documentOpened ()),
  617. this, TQT_SLOT (slotUpdateCaption ()));
  618. connect (m_document, TQT_SIGNAL (documentSaved ()),
  619. this, TQT_SLOT (slotUpdateCaption ()));
  620. // File/Reload action only available with non-empty URL
  621. connect (m_document, TQT_SIGNAL (documentSaved ()),
  622. this, TQT_SLOT (slotEnableReload ()));
  623. connect (m_document, TQT_SIGNAL (documentSaved ()),
  624. this, TQT_SLOT (slotEnableSettingsShowPath ()));
  625. // Command history
  626. if (m_commandHistory)
  627. {
  628. connect (m_commandHistory, TQT_SIGNAL (documentRestored ()),
  629. this, TQT_SLOT (slotDocumentRestored ())); // caption "!modified"
  630. connect (m_document, TQT_SIGNAL (documentSaved ()),
  631. m_commandHistory, TQT_SLOT (documentSaved ()));
  632. }
  633. else
  634. {
  635. kdError () << "kpMainWindow::setDocument() without commandHistory"
  636. << endl;
  637. }
  638. // Sync document -> views
  639. connect (m_document, TQT_SIGNAL (contentsChanged (const TQRect &)),
  640. m_viewManager, TQT_SLOT (updateViews (const TQRect &)));
  641. connect (m_document, TQT_SIGNAL (sizeChanged (int, int)),
  642. m_viewManager, TQT_SLOT (adjustViewsToEnvironment ()));
  643. #if DEBUG_KP_MAIN_WINDOW
  644. kdDebug () << "\tenabling actions" << endl;
  645. #endif
  646. // sync with the bit marked "sync" above
  647. if (m_colorToolBar)
  648. m_colorToolBar->setEnabled (true);
  649. else
  650. {
  651. kdError () << "kpMainWindow::setDocument() without colorToolBar"
  652. << endl;
  653. }
  654. // Hide the text toolbar - it will be shown by kpToolText::begin()
  655. enableTextToolBarActions (false);
  656. enableToolsDocumentActions (true);
  657. enableDocumentActions (true);
  658. // TODO: The thumbnail auto zoom doesn't work because it thinks its
  659. // width == 1 when !this->isShown(). So for consistency,
  660. // never create the thumbnail.
  661. #if 0
  662. if (m_configThumbnailShown)
  663. {
  664. if (isShown ())
  665. {
  666. #if DEBUG_KP_MAIN_WINDOW
  667. kdDebug () << "\tcreating thumbnail immediately" << endl;
  668. #endif
  669. slotCreateThumbnail ();
  670. }
  671. // this' geometry is weird ATM
  672. else
  673. {
  674. #if DEBUG_KP_MAIN_WINDOW
  675. kdDebug () << "\tcreating thumbnail LATER" << endl;
  676. #endif
  677. TQTimer::singleShot (0, this, TQT_SLOT (slotCreateThumbnail ()));
  678. }
  679. }
  680. #endif
  681. }
  682. #if DEBUG_KP_MAIN_WINDOW
  683. kdDebug () << "\tupdating mainWindow elements" << endl;
  684. #endif
  685. slotImageMenuUpdateDueToSelection ();
  686. recalculateStatusBar ();
  687. slotUpdateCaption (); // Untitled to start with
  688. slotEnableReload ();
  689. slotEnableSettingsShowPath ();
  690. if (m_commandHistory)
  691. m_commandHistory->clear ();
  692. #if DEBUG_KP_MAIN_WINDOW
  693. kdDebug () << "\tdocument and views ready to go!" << endl;
  694. #endif
  695. }
  696. // private virtual [base KMainWindow]
  697. bool kpMainWindow::queryClose ()
  698. {
  699. #if DEBUG_KP_MAIN_WINDOW
  700. kdDebug () << "kpMainWindow::queryClose()" << endl;
  701. #endif
  702. if (toolHasBegunShape ())
  703. tool ()->endShapeInternal ();
  704. if (!m_document || !m_document->isModified ())
  705. return true; // ok to close current doc
  706. int result = KMessageBox::warningYesNoCancel (this,
  707. i18n ("The document \"%1\" has been modified.\n"
  708. "Do you want to save it?")
  709. .arg (m_document->prettyFilename ()),
  710. TQString()/*caption*/,
  711. KStdGuiItem::save (), KStdGuiItem::discard ());
  712. switch (result)
  713. {
  714. case KMessageBox::Yes:
  715. return slotSave (); // close only if save succeeds
  716. case KMessageBox::No:
  717. return true; // close without saving
  718. default:
  719. return false; // don't close current doc
  720. }
  721. }
  722. // private virtual [base TQWidget]
  723. void kpMainWindow::dragEnterEvent (TQDragEnterEvent *e)
  724. {
  725. e->accept (kpSelectionDrag::canDecode (e) ||
  726. KURLDrag::canDecode (e) ||
  727. TQTextDrag::canDecode (e));
  728. }
  729. // private virtual [base TQWidget]
  730. void kpMainWindow::dropEvent (TQDropEvent *e)
  731. {
  732. #if DEBUG_KP_MAIN_WINDOW
  733. kdDebug () << "kpMainWindow::dropEvent" << e->pos () << endl;
  734. #endif
  735. kpSelection sel;
  736. KURL::List urls;
  737. TQString text;
  738. if (kpSelectionDrag::decode (e, sel/*ref*/, pasteWarnAboutLossInfo ()))
  739. {
  740. sel.setTransparency (selectionTransparency ());
  741. // TODO: drop at point like with TQTextDrag below?
  742. paste (sel);
  743. }
  744. else if (KURLDrag::decode (e, urls/*ref*/))
  745. {
  746. for (KURL::List::ConstIterator it = urls.begin (); it != urls.end (); it++)
  747. {
  748. open (*it);
  749. }
  750. }
  751. else if (TQTextDrag::decode (e, text/*ref*/))
  752. {
  753. TQPoint selTopLeft = KP_INVALID_POINT;
  754. const TQPoint globalPos = TQWidget::mapToGlobal (e->pos ());
  755. #if DEBUG_KP_MAIN_WINDOW
  756. kdDebug () << "\tpos toGlobal=" << globalPos << endl;
  757. #endif
  758. kpView *view = 0;
  759. if (m_viewManager)
  760. {
  761. view = m_viewManager->viewUnderCursor ();
  762. #if DEBUG_KP_MAIN_WINDOW
  763. kdDebug () << "\t\tviewUnderCursor=" << view << endl;
  764. #endif
  765. if (!view)
  766. {
  767. // HACK: see kpViewManager::setViewUnderCursor() to see why
  768. // it's not reliable
  769. #if DEBUG_KP_MAIN_WINDOW
  770. kdDebug () << "\t\tattempting to discover view" << endl;
  771. if (m_mainView && m_scrollView)
  772. {
  773. kdDebug () << "\t\t\tmainView->globalRect="
  774. << kpWidgetMapper::toGlobal (m_mainView, m_mainView->rect ())
  775. << " scrollView->globalRect="
  776. << kpWidgetMapper::toGlobal (m_scrollView,
  777. TQRect (0, 0,
  778. m_scrollView->visibleWidth (),
  779. m_scrollView->visibleHeight ()))
  780. << endl;
  781. }
  782. #endif
  783. if (m_thumbnailView &&
  784. kpWidgetMapper::toGlobal (m_thumbnailView, m_thumbnailView->rect ())
  785. .contains (globalPos))
  786. {
  787. // TODO: Code will never get executed.
  788. // Thumbnail doesn't accept drops.
  789. view = m_thumbnailView;
  790. }
  791. else if (m_mainView &&
  792. kpWidgetMapper::toGlobal (m_mainView, m_mainView->rect ())
  793. .contains (globalPos) &&
  794. m_scrollView &&
  795. kpWidgetMapper::toGlobal (m_scrollView,
  796. TQRect (0, 0,
  797. m_scrollView->visibleWidth (),
  798. m_scrollView->visibleHeight ()))
  799. .contains (globalPos))
  800. {
  801. view = m_mainView;
  802. }
  803. }
  804. }
  805. if (view)
  806. {
  807. const TQPoint viewPos = view->mapFromGlobal (globalPos);
  808. const TQPoint docPoint = view->transformViewToDoc (viewPos);
  809. // viewUnderCursor() is hacky and can return a view when we aren't
  810. // over one thanks to drags.
  811. if (m_document && m_document->rect ().contains (docPoint))
  812. {
  813. selTopLeft = docPoint;
  814. // TODO: In terms of doc pixels, would be inconsistent behaviour
  815. // based on zoomLevel of view.
  816. // selTopLeft -= TQPoint (-view->selectionResizeHandleAtomicSize (),
  817. // -view->selectionResizeHandleAtomicSize ());
  818. }
  819. }
  820. pasteText (text, true/*force new text selection*/, selTopLeft);
  821. }
  822. }
  823. // private slot
  824. void kpMainWindow::slotScrollViewAboutToScroll ()
  825. {
  826. #if DEBUG_KP_MAIN_WINDOW && 0
  827. kdDebug () << "kpMainWindow::slotScrollViewAboutToScroll() tool="
  828. << tool () << " viewManager=" << viewManager () << endl;
  829. if (viewManager ())
  830. {
  831. kdDebug () << "\tfastUpdates=" << viewManager ()->fastUpdates ()
  832. << " queueUpdates=" << viewManager ()->queueUpdates ()
  833. << endl;
  834. }
  835. else
  836. {
  837. // We're getting a late signal from the scrollview (thanks to
  838. // a timer inside the TQScrollView). By now, setDocument() has
  839. // already killed the document(), tool() and viewManager().
  840. }
  841. #endif
  842. TQTimer::singleShot (0, this, TQT_SLOT (slotScrollViewAfterScroll ()));
  843. }
  844. // private slot
  845. void kpMainWindow::slotScrollViewAfterScroll ()
  846. {
  847. #if DEBUG_KP_MAIN_WINDOW && 0
  848. kdDebug () << "kpMainWindow::slotScrollViewAfterScroll() tool="
  849. << tool () << endl;
  850. #endif
  851. if (tool ())
  852. {
  853. tool ()->somethingBelowTheCursorChanged ();
  854. }
  855. }
  856. // private virtual [base TQWidget]
  857. void kpMainWindow::moveEvent (TQMoveEvent * /*e*/)
  858. {
  859. if (m_thumbnail)
  860. {
  861. // Disabled because it lags too far behind the mainWindow
  862. // m_thumbnail->move (m_thumbnail->pos () + (e->pos () - e->oldPos ()));
  863. notifyThumbnailGeometryChanged ();
  864. }
  865. }
  866. // private slot
  867. void kpMainWindow::slotUpdateCaption ()
  868. {
  869. if (m_document)
  870. {
  871. setCaption (m_configShowPath ? m_document->prettyURL ()
  872. : m_document->prettyFilename (),
  873. m_document->isModified ());
  874. }
  875. else
  876. {
  877. setCaption (TQString(), false);
  878. }
  879. }
  880. // private slot
  881. void kpMainWindow::slotDocumentRestored ()
  882. {
  883. if (m_document)
  884. m_document->setModified (false);
  885. slotUpdateCaption ();
  886. }
  887. #include <kpmainwindow.moc>