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_view.cpp 34KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  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_ZOOM_FLICKER 0
  24. #include <kpmainwindow.h>
  25. #include <kpmainwindow_p.h>
  26. #include <tqdatetime.h>
  27. #include <tqpainter.h>
  28. #include <tqtimer.h>
  29. #include <tdeactionclasses.h>
  30. #include <tdeapplication.h>
  31. #include <tdeconfig.h>
  32. #include <kdebug.h>
  33. #include <tdelocale.h>
  34. #include <kstdaction.h>
  35. #include <kpdefs.h>
  36. #include <kpdocument.h>
  37. #include <kpthumbnail.h>
  38. #include <kptool.h>
  39. #include <kptooltoolbar.h>
  40. #include <kpunzoomedthumbnailview.h>
  41. #include <kpviewmanager.h>
  42. #include <kpviewscrollablecontainer.h>
  43. #include <kpwidgetmapper.h>
  44. #include <kpzoomedview.h>
  45. #include <kpzoomedthumbnailview.h>
  46. // private
  47. void kpMainWindow::setupViewMenuActions ()
  48. {
  49. m_viewMenuDocumentActionsEnabled = false;
  50. m_thumbnailSaveConfigTimer = 0;
  51. TDEActionCollection *ac = actionCollection ();
  52. /*m_actionFullScreen = KStdAction::fullScreen (0, 0, ac);
  53. m_actionFullScreen->setEnabled (false);*/
  54. m_actionActualSize = KStdAction::actualSize (TQT_TQOBJECT(this), TQT_SLOT (slotActualSize ()), ac);
  55. /*m_actionFitToPage = KStdAction::fitToPage (TQT_TQOBJECT(this), TQT_SLOT (slotFitToPage ()), ac);
  56. m_actionFitToWidth = KStdAction::fitToWidth (TQT_TQOBJECT(this), TQT_SLOT (slotFitToWidth ()), ac);
  57. m_actionFitToHeight = KStdAction::fitToHeight (TQT_TQOBJECT(this), TQT_SLOT (slotFitToHeight ()), ac);*/
  58. m_actionZoomIn = KStdAction::zoomIn (TQT_TQOBJECT(this), TQT_SLOT (slotZoomIn ()), ac);
  59. m_actionZoomOut = KStdAction::zoomOut (TQT_TQOBJECT(this), TQT_SLOT (slotZoomOut ()), ac);
  60. m_actionZoom = new TDESelectAction (i18n ("&Zoom"), 0,
  61. TQT_TQOBJECT(this), TQT_SLOT (slotZoom ()), actionCollection (), "view_zoom_to");
  62. m_actionZoom->setEditable (true);
  63. // create the zoom list for the 1st call to zoomTo() below
  64. m_zoomList.append (10); m_zoomList.append (25); m_zoomList.append (33);
  65. m_zoomList.append (50); m_zoomList.append (67); m_zoomList.append (75);
  66. m_zoomList.append (100);
  67. m_zoomList.append (200); m_zoomList.append (300);
  68. m_zoomList.append (400); m_zoomList.append (600); m_zoomList.append (800);
  69. m_zoomList.append (1000); m_zoomList.append (1200); m_zoomList.append (1600);
  70. m_actionShowGrid = new TDEToggleAction (i18n ("Show &Grid"), CTRL + Key_G,
  71. TQT_TQOBJECT(this), TQT_SLOT (slotShowGridToggled ()), actionCollection (), "view_show_grid");
  72. m_actionShowGrid->setCheckedState (i18n ("Hide &Grid"));
  73. // TODO: This doesn't work when the thumbnail has focus.
  74. // Testcase: Press CTRL+H twice on a fresh KolourPaint.
  75. // The second CTRL+H doesn't close the thumbnail.
  76. m_actionShowThumbnail = new TDEToggleAction (i18n ("Show T&humbnail"), CTRL + Key_H,
  77. TQT_TQOBJECT(this), TQT_SLOT (slotShowThumbnailToggled ()), actionCollection (), "view_show_thumbnail");
  78. m_actionShowThumbnail->setCheckedState (i18n ("Hide T&humbnail"));
  79. // Please do not use setCheckedState() here - it wouldn't make sense
  80. m_actionZoomedThumbnail = new TDEToggleAction (i18n ("Zoo&med Thumbnail Mode"), 0,
  81. TQT_TQOBJECT(this), TQT_SLOT (slotZoomedThumbnailToggled ()), actionCollection (), "view_zoomed_thumbnail");
  82. // For consistency with the above action, don't use setCheckedState()
  83. //
  84. // Also, don't use "Show Thumbnail Rectangle" because if entire doc
  85. // can be seen in scrollView, checking option won't "Show" anything
  86. // since rect _surrounds_ entire doc (hence, won't be rendered).
  87. d->m_actionShowThumbnailRectangle = new TDEToggleAction (
  88. i18n ("Enable Thumbnail &Rectangle"),
  89. 0,
  90. TQT_TQOBJECT(this), TQT_SLOT (slotThumbnailShowRectangleToggled ()),
  91. actionCollection (), "view_show_thumbnail_rectangle");
  92. enableViewMenuDocumentActions (false);
  93. }
  94. // private
  95. bool kpMainWindow::viewMenuDocumentActionsEnabled () const
  96. {
  97. return m_viewMenuDocumentActionsEnabled;
  98. }
  99. // private
  100. void kpMainWindow::enableViewMenuDocumentActions (bool enable)
  101. {
  102. m_viewMenuDocumentActionsEnabled = enable;
  103. m_actionActualSize->setEnabled (enable);
  104. /*m_actionFitToPage->setEnabled (enable);
  105. m_actionFitToWidth->setEnabled (enable);
  106. m_actionFitToHeight->setEnabled (enable);*/
  107. m_actionZoomIn->setEnabled (enable);
  108. m_actionZoomOut->setEnabled (enable);
  109. m_actionZoom->setEnabled (enable);
  110. actionShowGridUpdate ();
  111. m_actionShowThumbnail->setEnabled (enable);
  112. enableThumbnailOptionActions (enable);
  113. // TODO: for the time being, assume that we start at zoom 100%
  114. // with no grid
  115. // This function is only called when a new document is created
  116. // or an existing document is closed. So the following will
  117. // always be correct:
  118. zoomTo (100);
  119. }
  120. // private
  121. void kpMainWindow::actionShowGridUpdate ()
  122. {
  123. #if DEBUG_KP_MAIN_WINDOW
  124. kdDebug () << "kpMainWindow::actionShowGridUpdate()" << endl;
  125. #endif
  126. const bool enable = (viewMenuDocumentActionsEnabled () &&
  127. m_mainView && m_mainView->canShowGrid ());
  128. m_actionShowGrid->setEnabled (enable);
  129. m_actionShowGrid->setChecked (enable && m_configShowGrid);
  130. }
  131. // private
  132. void kpMainWindow::sendZoomListToActionZoom ()
  133. {
  134. TQStringList items;
  135. const TQValueVector <int>::ConstIterator zoomListEnd (m_zoomList.end ());
  136. for (TQValueVector <int>::ConstIterator it = m_zoomList.begin ();
  137. it != zoomListEnd;
  138. it++)
  139. {
  140. items << zoomLevelToString (*it);
  141. }
  142. // Work around a KDE bug - TDESelectAction::setItems() enables the action.
  143. // David Faure said it won't be fixed because it's a feature used by
  144. // TDERecentFilesAction.
  145. bool e = m_actionZoom->isEnabled ();
  146. m_actionZoom->setItems (items);
  147. if (e != m_actionZoom->isEnabled ())
  148. m_actionZoom->setEnabled (e);
  149. }
  150. // private
  151. int kpMainWindow::zoomLevelFromString (const TQString &string)
  152. {
  153. // loop until not digit
  154. int i;
  155. for (i = 0; i < (int) string.length () && string.at (i).isDigit (); i++)
  156. ;
  157. // convert zoom level to number
  158. bool ok = false;
  159. int zoomLevel = string.left (i).toInt (&ok);
  160. if (!ok || zoomLevel <= 0 || zoomLevel > 3200)
  161. return 0; // error
  162. else
  163. return zoomLevel;
  164. }
  165. // private
  166. TQString kpMainWindow::zoomLevelToString (int zoomLevel)
  167. {
  168. return i18n ("%1%").arg (zoomLevel);
  169. }
  170. // private
  171. void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor)
  172. {
  173. #if DEBUG_KP_MAIN_WINDOW
  174. kdDebug () << "kpMainWindow::zoomTo (" << zoomLevel << ")" << endl;
  175. #endif
  176. if (zoomLevel <= 0)
  177. zoomLevel = m_mainView ? m_mainView->zoomLevelX () : 100;
  178. // mute point since the thumbnail suffers from this too
  179. #if 0
  180. else if (m_mainView && m_mainView->zoomLevelX () % 100 == 0 && zoomLevel % 100)
  181. {
  182. if (KMessageBox::warningContinueCancel (this,
  183. i18n ("Setting the zoom level to a value that is not a multiple of 100% "
  184. "results in imprecise editing and redraw glitches.\n"
  185. "Do you really want to set to zoom level to %1%?")
  186. .arg (zoomLevel),
  187. TQString()/*caption*/,
  188. i18n ("Set Zoom Level to %1%").arg (zoomLevel),
  189. "DoNotAskAgain_ZoomLevelNotMultipleOf100") != KMessageBox::Continue)
  190. {
  191. zoomLevel = m_mainView->zoomLevelX ();
  192. }
  193. }
  194. #endif
  195. int index = 0;
  196. TQValueVector <int>::Iterator it = m_zoomList.begin ();
  197. while (index < (int) m_zoomList.count () && zoomLevel > *it)
  198. it++, index++;
  199. if (zoomLevel != *it)
  200. m_zoomList.insert (it, zoomLevel);
  201. sendZoomListToActionZoom ();
  202. m_actionZoom->setCurrentItem (index);
  203. if (viewMenuDocumentActionsEnabled ())
  204. {
  205. m_actionActualSize->setEnabled (zoomLevel != 100);
  206. m_actionZoomIn->setEnabled (m_actionZoom->currentItem () < (int) m_zoomList.count () - 1);
  207. m_actionZoomOut->setEnabled (m_actionZoom->currentItem () > 0);
  208. }
  209. if (m_viewManager)
  210. m_viewManager->setQueueUpdates ();
  211. if (m_scrollView)
  212. {
  213. m_scrollView->setUpdatesEnabled (false);
  214. if (m_scrollView->viewport ())
  215. m_scrollView->viewport ()->setUpdatesEnabled (false);
  216. }
  217. if (m_mainView)
  218. {
  219. m_mainView->setUpdatesEnabled (false);
  220. if (m_scrollView && m_scrollView->viewport ())
  221. {
  222. // Ordinary flicker is better than the whole view moving
  223. TQPainter p (m_mainView);
  224. p.fillRect (m_mainView->rect (),
  225. m_scrollView->viewport ()->colorGroup ().background ());
  226. }
  227. }
  228. if (m_scrollView && m_mainView)
  229. {
  230. #if DEBUG_KP_MAIN_WINDOW && 1
  231. kdDebug () << "\tscrollView contentsX=" << m_scrollView->contentsX ()
  232. << " contentsY=" << m_scrollView->contentsY ()
  233. << " contentsWidth=" << m_scrollView->contentsWidth ()
  234. << " contentsHeight=" << m_scrollView->contentsHeight ()
  235. << " visibleWidth=" << m_scrollView->visibleWidth ()
  236. << " visibleHeight=" << m_scrollView->visibleHeight ()
  237. << " oldZoomX=" << m_mainView->zoomLevelX ()
  238. << " oldZoomY=" << m_mainView->zoomLevelY ()
  239. << " newZoom=" << zoomLevel
  240. << " mainViewX=" << m_scrollView->childX (m_mainView)
  241. << " mainViewY=" << m_scrollView->childY (m_mainView)
  242. << endl;
  243. #endif
  244. // TODO: when changing from no scrollbars to scrollbars, TQt lies about
  245. // visibleWidth() & visibleHeight() (doesn't take into account the
  246. // space taken by the would-be scrollbars) until it updates the
  247. // scrollview; hence the centring is off by about 5-10 pixels.
  248. // TODO: use visibleRect() for greater accuracy?
  249. int viewX, viewY;
  250. bool targetDocAvail = false;
  251. double targetDocX, targetDocY;
  252. if (centerUnderCursor &&
  253. m_viewManager && m_viewManager->viewUnderCursor ())
  254. {
  255. kpView *const vuc = m_viewManager->viewUnderCursor ();
  256. TQPoint viewPoint = vuc->mouseViewPoint ();
  257. // vuc->transformViewToDoc() returns TQPoint which only has int
  258. // accuracy so we do X and Y manually.
  259. targetDocX = vuc->transformViewToDocX (viewPoint.x ());
  260. targetDocY = vuc->transformViewToDocY (viewPoint.y ());
  261. targetDocAvail = true;
  262. if (vuc != m_mainView)
  263. viewPoint = vuc->transformViewToOtherView (viewPoint, m_mainView);
  264. viewX = viewPoint.x ();
  265. viewY = viewPoint.y ();
  266. }
  267. else
  268. {
  269. viewX = m_scrollView->contentsX () +
  270. TQMIN (m_mainView->width (),
  271. m_scrollView->visibleWidth ()) / 2;
  272. viewY = m_scrollView->contentsY () +
  273. TQMIN (m_mainView->height (),
  274. m_scrollView->visibleHeight ()) / 2;
  275. }
  276. int newCenterX = viewX * zoomLevel / m_mainView->zoomLevelX ();
  277. int newCenterY = viewY * zoomLevel / m_mainView->zoomLevelY ();
  278. m_mainView->setZoomLevel (zoomLevel, zoomLevel);
  279. #if DEBUG_ZOOM_FLICKER
  280. {
  281. kdDebug () << "FLICKER: just setZoomLevel" << endl;
  282. TQTime timer; timer.start ();
  283. while (timer.elapsed () < 1000)
  284. ;
  285. }
  286. #endif
  287. #if DEBUG_KP_MAIN_WINDOW && 1
  288. kdDebug () << "\tvisibleWidth=" << m_scrollView->visibleWidth ()
  289. << " visibleHeight=" << m_scrollView->visibleHeight ()
  290. << endl;
  291. kdDebug () << "\tnewCenterX=" << newCenterX
  292. << " newCenterY=" << newCenterY << endl;
  293. #endif
  294. m_scrollView->center (newCenterX, newCenterY);
  295. #if DEBUG_ZOOM_FLICKER
  296. {
  297. kdDebug () << "FLICKER: just centred" << endl;
  298. TQTime timer; timer.start ();
  299. while (timer.elapsed () < 2000)
  300. ;
  301. }
  302. #endif
  303. if (centerUnderCursor &&
  304. targetDocAvail &&
  305. m_viewManager && m_viewManager->viewUnderCursor ())
  306. {
  307. kpView *const vuc = m_viewManager->viewUnderCursor ();
  308. #if DEBUG_KP_MAIN_WINDOW
  309. kdDebug () << "\tcenterUnderCursor: reposition cursor; viewUnderCursor="
  310. << vuc->name () << endl;
  311. #endif
  312. const double viewX = vuc->transformDocToViewX (targetDocX);
  313. const double viewY = vuc->transformDocToViewY (targetDocY);
  314. // Rounding error from zooming in and out :(
  315. // TODO: do everything in terms of tool doc points in type "double".
  316. const TQPoint viewPoint ((int) viewX, (int) viewY);
  317. #if DEBUG_KP_MAIN_WINDOW
  318. kdDebug () << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")"
  319. << " viewUnderCursor: (" << viewX << "," << viewY << ")"
  320. << endl;
  321. #endif
  322. if (vuc->clipRegion ().contains (viewPoint))
  323. {
  324. const TQPoint globalPoint =
  325. kpWidgetMapper::toGlobal (vuc, viewPoint);
  326. #if DEBUG_KP_MAIN_WINDOW
  327. kdDebug () << "\t\tglobalPoint=" << globalPoint << endl;
  328. #endif
  329. // TODO: Determine some sane cursor flashing indication -
  330. // cursor movement is convenient but not conventional.
  331. //
  332. // Major problem: if using TQApplication::setOverrideCursor()
  333. // and in some stage of flash and window quits.
  334. //
  335. // Or if using kpView::setCursor() and change tool.
  336. TQCursor::setPos (globalPoint);
  337. }
  338. // e.g. Zoom to 200%, scroll mainView to bottom-right.
  339. // Unzoomed Thumbnail shows top-left portion of bottom-right of
  340. // mainView.
  341. //
  342. // Aim cursor at bottom-right of thumbnail and zoom out with
  343. // CTRL+Wheel.
  344. //
  345. // If mainView is now small enough to largely not need scrollbars,
  346. // Unzoomed Thumbnail scrolls to show _top-left_ portion
  347. // _of top-left_ of mainView.
  348. //
  349. // Unzoomed Thumbnail no longer contains the point we zoomed out
  350. // on top of.
  351. else
  352. {
  353. #if DEBUG_KP_MAIN_WINDOW
  354. kdDebug () << "\t\twon't move cursor - would get outside view"
  355. << endl;
  356. #endif
  357. // TODO: Sane cursor flashing indication that indicates
  358. // that the normal cursor movement didn't happen.
  359. }
  360. }
  361. #if DEBUG_KP_MAIN_WINDOW && 1
  362. kdDebug () << "\t\tcheck (contentsX=" << m_scrollView->contentsX ()
  363. << ",contentsY=" << m_scrollView->contentsY ()
  364. << ")" << endl;
  365. #endif
  366. }
  367. if (m_mainView)
  368. {
  369. actionShowGridUpdate ();
  370. #if DEBUG_ZOOM_FLICKER
  371. {
  372. kdDebug () << "FLICKER: updated grid action" << endl;
  373. TQTime timer; timer.start ();
  374. while (timer.elapsed () < 1000)
  375. ;
  376. }
  377. #endif
  378. updateMainViewGrid ();
  379. #if DEBUG_ZOOM_FLICKER
  380. {
  381. kdDebug () << "FLICKER: just updated grid" << endl;
  382. TQTime timer; timer.start ();
  383. while (timer.elapsed () < 1000)
  384. ;
  385. }
  386. #endif
  387. // Since Zoom Level TDESelectAction on ToolBar grabs focus after changing
  388. // Zoom, switch back to the Main View.
  389. // TODO: back to the last view
  390. m_mainView->setFocus ();
  391. #if DEBUG_ZOOM_FLICKER
  392. {
  393. kdDebug () << "FLICKER: just set focus to mainview" << endl;
  394. TQTime timer; timer.start ();
  395. while (timer.elapsed () < 1000)
  396. ;
  397. }
  398. #endif
  399. }
  400. #if 1
  401. // The view magnified and moved beneath the cursor
  402. if (tool ())
  403. tool ()->somethingBelowTheCursorChanged ();
  404. #if DEBUG_ZOOM_FLICKER
  405. {
  406. kdDebug () << "FLICKER: signalled something below cursor" << endl;
  407. TQTime timer; timer.start ();
  408. while (timer.elapsed () < 1000)
  409. ;
  410. }
  411. #endif
  412. #endif
  413. // HACK: make sure all of TQt's update() calls trigger
  414. // kpView::paintEvent() _now_ so that they can be queued by us
  415. // (until kpViewManager::restoreQueueUpdates()) to reduce flicker
  416. // caused mainly by m_scrollView->center()
  417. //
  418. // TODO: remove flicker completely
  419. //TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT (finishZoomTo ()));
  420. // Later: I don't think there is an update() that needs to be queued
  421. // - let's reduce latency instead.
  422. finishZoomTo ();
  423. }
  424. // private slot
  425. void kpMainWindow::finishZoomTo ()
  426. {
  427. #if DEBUG_KP_MAIN_WINDOW && 1
  428. kdDebug () << "\tkpMainWindow::finishZoomTo enter" << endl;
  429. #endif
  430. #if DEBUG_ZOOM_FLICKER
  431. {
  432. kdDebug () << "FLICKER: inside finishZoomTo" << endl;
  433. TQTime timer; timer.start ();
  434. while (timer.elapsed () < 2000)
  435. ;
  436. }
  437. #endif
  438. // TODO: setUpdatesEnabled() should really return to old value
  439. // - not neccessarily "true"
  440. if (m_mainView)
  441. {
  442. m_mainView->setUpdatesEnabled (true);
  443. m_mainView->update ();
  444. }
  445. #if DEBUG_ZOOM_FLICKER
  446. {
  447. kdDebug () << "FLICKER: just updated mainView" << endl;
  448. TQTime timer; timer.start ();
  449. while (timer.elapsed () < 1000)
  450. ;
  451. }
  452. #endif
  453. if (m_scrollView)
  454. {
  455. if (m_scrollView->viewport ())
  456. {
  457. m_scrollView->viewport ()->setUpdatesEnabled (true);
  458. m_scrollView->viewport ()->update ();
  459. }
  460. #if DEBUG_ZOOM_FLICKER
  461. {
  462. kdDebug () << "FLICKER: just updated scrollView::viewport()" << endl;
  463. TQTime timer; timer.start ();
  464. while (timer.elapsed () < 1000)
  465. ;
  466. }
  467. #endif
  468. m_scrollView->setUpdatesEnabled (true);
  469. m_scrollView->update ();
  470. #if DEBUG_ZOOM_FLICKER
  471. {
  472. kdDebug () << "FLICKER: just updated scrollView" << endl;
  473. TQTime timer; timer.start ();
  474. while (timer.elapsed () < 1000)
  475. ;
  476. }
  477. #endif
  478. }
  479. if (m_viewManager && m_viewManager->queueUpdates ()/*just in case*/)
  480. m_viewManager->restoreQueueUpdates ();
  481. #if DEBUG_ZOOM_FLICKER
  482. {
  483. kdDebug () << "FLICKER: restored vm queued updates" << endl;
  484. TQTime timer; timer.start ();
  485. while (timer.elapsed () < 1000)
  486. ;
  487. }
  488. #endif
  489. setStatusBarZoom (m_mainView ? m_mainView->zoomLevelX () : 0);
  490. #if DEBUG_KP_MAIN_WINDOW && 1
  491. kdDebug () << "\tkpMainWindow::finishZoomTo done" << endl;
  492. #endif
  493. #if DEBUG_ZOOM_FLICKER
  494. {
  495. kdDebug () << "FLICKER: finishZoomTo done" << endl;
  496. TQTime timer; timer.start ();
  497. while (timer.elapsed () < 1000)
  498. ;
  499. }
  500. #endif
  501. }
  502. // private slot
  503. void kpMainWindow::slotActualSize ()
  504. {
  505. zoomTo (100);
  506. }
  507. // private slot
  508. void kpMainWindow::slotFitToPage ()
  509. {
  510. if (!m_scrollView || !m_document)
  511. return;
  512. // doc_width * zoom / 100 <= view_width &&
  513. // doc_height * zoom / 100 <= view_height &&
  514. // 1 <= zoom <= 3200
  515. zoomTo (TQMIN (3200, TQMAX (1, TQMIN (m_scrollView->visibleWidth () * 100 / m_document->width (),
  516. m_scrollView->visibleHeight () * 100 / m_document->height ()))));
  517. }
  518. // private slot
  519. void kpMainWindow::slotFitToWidth ()
  520. {
  521. if (!m_scrollView || !m_document)
  522. return;
  523. // doc_width * zoom / 100 <= view_width &&
  524. // 1 <= zoom <= 3200
  525. zoomTo (TQMIN (3200, TQMAX (1, m_scrollView->visibleWidth () * 100 / m_document->width ())));
  526. }
  527. // private slot
  528. void kpMainWindow::slotFitToHeight ()
  529. {
  530. if (!m_scrollView || !m_document)
  531. return;
  532. // doc_height * zoom / 100 <= view_height &&
  533. // 1 <= zoom <= 3200
  534. zoomTo (TQMIN (3200, TQMAX (1, m_scrollView->visibleHeight () * 100 / m_document->height ())));
  535. }
  536. // public
  537. void kpMainWindow::zoomIn (bool centerUnderCursor)
  538. {
  539. const int targetItem = m_actionZoom->currentItem () + 1;
  540. if (targetItem >= (int) m_zoomList.count ())
  541. return;
  542. m_actionZoom->setCurrentItem (targetItem);
  543. zoomAccordingToZoomAction (centerUnderCursor);
  544. }
  545. // public
  546. void kpMainWindow::zoomOut (bool centerUnderCursor)
  547. {
  548. const int targetItem = m_actionZoom->currentItem () - 1;
  549. if (targetItem < 0)
  550. return;
  551. m_actionZoom->setCurrentItem (targetItem);
  552. zoomAccordingToZoomAction (centerUnderCursor);
  553. }
  554. // public slot
  555. void kpMainWindow::slotZoomIn ()
  556. {
  557. #if DEBUG_KP_MAIN_WINDOW
  558. kdDebug () << "kpMainWindow::slotZoomIn ()" << endl;
  559. #endif
  560. zoomIn (false/*don't center under cursor*/);
  561. }
  562. // public slot
  563. void kpMainWindow::slotZoomOut ()
  564. {
  565. #if DEBUG_KP_MAIN_WINDOW
  566. kdDebug () << "kpMainWindow::slotZoomOut ()" << endl;
  567. #endif
  568. zoomOut (false/*don't center under cursor*/);
  569. }
  570. // public
  571. void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor)
  572. {
  573. zoomTo (zoomLevelFromString (m_actionZoom->currentText ()),
  574. centerUnderCursor);
  575. }
  576. // private slot
  577. void kpMainWindow::slotZoom ()
  578. {
  579. #if DEBUG_KP_MAIN_WINDOW
  580. kdDebug () << "kpMainWindow::slotZoom () index=" << m_actionZoom->currentItem ()
  581. << " text='" << m_actionZoom->currentText () << "'" << endl;
  582. #endif
  583. zoomAccordingToZoomAction (false/*don't center under cursor*/);
  584. }
  585. // private slot
  586. void kpMainWindow::slotShowGridToggled ()
  587. {
  588. #if DEBUG_KP_MAIN_WINDOW
  589. kdDebug () << "kpMainWindow::slotActionShowGridToggled()" << endl;
  590. #endif
  591. updateMainViewGrid ();
  592. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
  593. TDEConfigBase *cfg = cfgGroupSaver.config ();
  594. cfg->writeEntry (kpSettingShowGrid, m_configShowGrid = m_actionShowGrid->isChecked ());
  595. cfg->sync ();
  596. }
  597. // private
  598. void kpMainWindow::updateMainViewGrid ()
  599. {
  600. #if DEBUG_KP_MAIN_WINDOW
  601. kdDebug () << "kpMainWindow::updateMainViewGrid ()" << endl;
  602. #endif
  603. if (m_mainView)
  604. m_mainView->showGrid (m_actionShowGrid->isChecked ());
  605. }
  606. // private
  607. TQRect kpMainWindow::mapToGlobal (const TQRect &rect) const
  608. {
  609. return kpWidgetMapper::toGlobal (this, rect);
  610. }
  611. // private
  612. TQRect kpMainWindow::mapFromGlobal (const TQRect &rect) const
  613. {
  614. return kpWidgetMapper::fromGlobal (this, rect);
  615. }
  616. // public slot
  617. void kpMainWindow::slotDestroyThumbnailIfNotVisible (bool tnIsVisible)
  618. {
  619. #if DEBUG_KP_MAIN_WINDOW
  620. kdDebug () << "kpMainWindow::slotDestroyThumbnailIfNotVisible(isVisible="
  621. << tnIsVisible
  622. << ")"
  623. << endl;
  624. #endif
  625. if (!tnIsVisible)
  626. {
  627. slotDestroyThumbnailInitatedByUser ();
  628. }
  629. }
  630. // private slot
  631. void kpMainWindow::slotDestroyThumbnail ()
  632. {
  633. #if DEBUG_KP_MAIN_WINDOW
  634. kdDebug () << "kpMainWindow::slotDestroyThumbnail()" << endl;
  635. #endif
  636. m_actionShowThumbnail->setChecked (false);
  637. enableThumbnailOptionActions (false);
  638. updateThumbnail ();
  639. }
  640. // private slot
  641. void kpMainWindow::slotDestroyThumbnailInitatedByUser ()
  642. {
  643. #if DEBUG_KP_MAIN_WINDOW
  644. kdDebug () << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()" << endl;
  645. #endif
  646. m_actionShowThumbnail->setChecked (false);
  647. slotShowThumbnailToggled ();
  648. }
  649. // private slot
  650. void kpMainWindow::slotCreateThumbnail ()
  651. {
  652. #if DEBUG_KP_MAIN_WINDOW
  653. kdDebug () << "kpMainWindow::slotCreateThumbnail()" << endl;
  654. #endif
  655. m_actionShowThumbnail->setChecked (true);
  656. enableThumbnailOptionActions (true);
  657. updateThumbnail ();
  658. }
  659. // public
  660. void kpMainWindow::notifyThumbnailGeometryChanged ()
  661. {
  662. #if DEBUG_KP_MAIN_WINDOW
  663. kdDebug () << "kpMainWindow::notifyThumbnailGeometryChanged()" << endl;
  664. #endif
  665. if (!m_thumbnailSaveConfigTimer)
  666. {
  667. m_thumbnailSaveConfigTimer = new TQTimer (this);
  668. connect (m_thumbnailSaveConfigTimer, TQT_SIGNAL (timeout ()),
  669. TQT_TQOBJECT(this), TQT_SLOT (slotSaveThumbnailGeometry ()));
  670. }
  671. m_thumbnailSaveConfigTimer->start (500/*msec*/, true/*single shot*/);
  672. }
  673. // private slot
  674. void kpMainWindow::slotSaveThumbnailGeometry ()
  675. {
  676. #if DEBUG_KP_MAIN_WINDOW
  677. kdDebug () << "kpMainWindow::saveThumbnailGeometry()" << endl;
  678. #endif
  679. if (!m_thumbnail)
  680. return;
  681. TQRect rect (m_thumbnail->x (), m_thumbnail->y (),
  682. m_thumbnail->width (), m_thumbnail->height ());
  683. #if DEBUG_KP_MAIN_WINDOW
  684. kdDebug () << "\tthumbnail relative geometry=" << rect << endl;
  685. #endif
  686. m_configThumbnailGeometry = mapFromGlobal (rect);
  687. #if DEBUG_KP_MAIN_WINDOW
  688. kdDebug () << "\tCONFIG: saving thumbnail geometry "
  689. << m_configThumbnailGeometry
  690. << endl;
  691. #endif
  692. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
  693. TDEConfigBase *cfg = cfgGroupSaver.config ();
  694. cfg->writeEntry (kpSettingThumbnailGeometry, m_configThumbnailGeometry);
  695. cfg->sync ();
  696. }
  697. // private slot
  698. void kpMainWindow::slotShowThumbnailToggled ()
  699. {
  700. #if DEBUG_KP_MAIN_WINDOW
  701. kdDebug () << "kpMainWindow::slotShowThumbnailToggled()" << endl;
  702. #endif
  703. m_configThumbnailShown = m_actionShowThumbnail->isChecked ();
  704. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
  705. TDEConfigBase *cfg = cfgGroupSaver.config ();
  706. cfg->writeEntry (kpSettingThumbnailShown, m_configThumbnailShown);
  707. cfg->sync ();
  708. enableThumbnailOptionActions (m_actionShowThumbnail->isChecked ());
  709. updateThumbnail ();
  710. }
  711. // private slot
  712. void kpMainWindow::updateThumbnailZoomed ()
  713. {
  714. #if DEBUG_KP_MAIN_WINDOW
  715. kdDebug () << "kpMainWindow::updateThumbnailZoomed() zoomed="
  716. << m_actionZoomedThumbnail->isChecked () << endl;
  717. #endif
  718. if (!m_thumbnailView)
  719. return;
  720. destroyThumbnailView ();
  721. createThumbnailView ();
  722. }
  723. // private slot
  724. void kpMainWindow::slotZoomedThumbnailToggled ()
  725. {
  726. #if DEBUG_KP_MAIN_WINDOW
  727. kdDebug () << "kpMainWindow::slotZoomedThumbnailToggled()" << endl;
  728. #endif
  729. m_configZoomedThumbnail = m_actionZoomedThumbnail->isChecked ();
  730. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
  731. TDEConfigBase *cfg = cfgGroupSaver.config ();
  732. cfg->writeEntry (kpSettingThumbnailZoomed, m_configZoomedThumbnail);
  733. cfg->sync ();
  734. updateThumbnailZoomed ();
  735. }
  736. // private slot
  737. void kpMainWindow::slotThumbnailShowRectangleToggled ()
  738. {
  739. #if DEBUG_KP_MAIN_WINDOW
  740. kdDebug () << "kpMainWindow::slotThumbnailShowRectangleToggled()" << endl;
  741. #endif
  742. d->m_configThumbnailShowRectangle = d->m_actionShowThumbnailRectangle->isChecked ();
  743. TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
  744. TDEConfigBase *cfg = cfgGroupSaver.config ();
  745. cfg->writeEntry (kpSettingThumbnailShowRectangle, d->m_configThumbnailShowRectangle);
  746. cfg->sync ();
  747. if (m_thumbnailView)
  748. {
  749. m_thumbnailView->showBuddyViewScrollableContainerRectangle (
  750. d->m_actionShowThumbnailRectangle->isChecked ());
  751. }
  752. }
  753. // private
  754. void kpMainWindow::enableViewZoomedThumbnail (bool enable)
  755. {
  756. #if DEBUG_KP_MAIN_WINDOW
  757. kdDebug () << "kpMainWindow::enableSettingsViewZoomedThumbnail()" << endl;
  758. #endif
  759. m_actionZoomedThumbnail->setEnabled (enable &&
  760. m_actionShowThumbnail->isChecked ());
  761. // Note: Don't uncheck if disabled - being able to see the zoomed state
  762. // before turning on the thumbnail can be useful.
  763. m_actionZoomedThumbnail->setChecked (m_configZoomedThumbnail);
  764. }
  765. // private
  766. void kpMainWindow::enableViewShowThumbnailRectangle (bool enable)
  767. {
  768. #if DEBUG_KP_MAIN_WINDOW
  769. kdDebug () << "kpMainWindow::enableViewShowThumbnailRectangle()" << endl;
  770. #endif
  771. d->m_actionShowThumbnailRectangle->setEnabled (enable &&
  772. m_actionShowThumbnail->isChecked ());
  773. // Note: Don't uncheck if disabled for consistency with
  774. // enableViewZoomedThumbnail()
  775. d->m_actionShowThumbnailRectangle->setChecked (
  776. d->m_configThumbnailShowRectangle);
  777. }
  778. // private
  779. void kpMainWindow::enableThumbnailOptionActions (bool enable)
  780. {
  781. enableViewZoomedThumbnail (enable);
  782. enableViewShowThumbnailRectangle (enable);
  783. }
  784. // private
  785. void kpMainWindow::createThumbnailView ()
  786. {
  787. #if DEBUG_KP_MAIN_WINDOW
  788. kdDebug () << "\t\tcreating new kpView:" << endl;
  789. #endif
  790. if (m_thumbnailView)
  791. {
  792. kdDebug () << "kpMainWindow::createThumbnailView() had to destroy view" << endl;
  793. destroyThumbnailView ();
  794. }
  795. if (m_actionZoomedThumbnail->isChecked ())
  796. {
  797. m_thumbnailView = new kpZoomedThumbnailView (
  798. m_document, m_toolToolBar, m_viewManager,
  799. m_mainView,
  800. 0/*scrollableContainer*/,
  801. m_thumbnail, "thumbnailView");
  802. }
  803. else
  804. {
  805. m_thumbnailView = new kpUnzoomedThumbnailView (
  806. m_document, m_toolToolBar, m_viewManager,
  807. m_mainView,
  808. 0/*scrollableContainer*/,
  809. m_thumbnail, "thumbnailView");
  810. }
  811. m_thumbnailView->showBuddyViewScrollableContainerRectangle (
  812. d->m_actionShowThumbnailRectangle->isChecked ());
  813. #if DEBUG_KP_MAIN_WINDOW
  814. kdDebug () << "\t\tgive kpThumbnail the kpView:" << endl;
  815. #endif
  816. if (m_thumbnail)
  817. m_thumbnail->setView (m_thumbnailView);
  818. else
  819. kdError () << "kpMainWindow::createThumbnailView() no thumbnail" << endl;
  820. #if DEBUG_KP_MAIN_WINDOW
  821. kdDebug () << "\t\tregistering the kpView:" << endl;
  822. #endif
  823. if (m_viewManager)
  824. m_viewManager->registerView (m_thumbnailView);
  825. }
  826. // private
  827. void kpMainWindow::destroyThumbnailView ()
  828. {
  829. if (!m_thumbnailView)
  830. return;
  831. if (m_viewManager)
  832. m_viewManager->unregisterView (m_thumbnailView);
  833. if (m_thumbnail)
  834. m_thumbnail->setView (0);
  835. m_thumbnailView->deleteLater (); m_thumbnailView = 0;
  836. }
  837. // private
  838. void kpMainWindow::updateThumbnail ()
  839. {
  840. #if DEBUG_KP_MAIN_WINDOW
  841. kdDebug () << "kpMainWindow::updateThumbnail()" << endl;
  842. #endif
  843. bool enable = m_actionShowThumbnail->isChecked ();
  844. #if DEBUG_KP_MAIN_WINDOW
  845. kdDebug () << "\tthumbnail="
  846. << bool (m_thumbnail)
  847. << " action_isChecked="
  848. << enable
  849. << endl;
  850. #endif
  851. if (bool (m_thumbnail) == enable)
  852. return;
  853. if (!m_thumbnail)
  854. {
  855. #if DEBUG_KP_MAIN_WINDOW
  856. kdDebug () << "\tcreating thumbnail" << endl;
  857. #endif
  858. // Read last saved geometry before creating thumbnail & friends
  859. // in case they call notifyThumbnailGeometryChanged()
  860. TQRect thumbnailGeometry = m_configThumbnailGeometry;
  861. #if DEBUG_KP_MAIN_WINDOW
  862. kdDebug () << "\t\tlast used geometry=" << thumbnailGeometry << endl;
  863. #endif
  864. m_thumbnail = new kpThumbnail (this, "thumbnail");
  865. createThumbnailView ();
  866. #if DEBUG_KP_MAIN_WINDOW
  867. kdDebug () << "\t\tmoving thumbnail to right place" << endl;
  868. #endif
  869. if (!thumbnailGeometry.isEmpty () &&
  870. TQRect (0, 0, width (), height ()).intersects (thumbnailGeometry))
  871. {
  872. const TQRect geometry = mapToGlobal (thumbnailGeometry);
  873. m_thumbnail->resize (geometry.size ());
  874. m_thumbnail->move (geometry.topLeft ());
  875. }
  876. else
  877. {
  878. if (m_scrollView)
  879. {
  880. const int margin = 20;
  881. const int initialWidth = 160, initialHeight = 120;
  882. TQRect geometryRect (width () - initialWidth - margin * 2,
  883. m_scrollView->y () + margin,
  884. initialWidth,
  885. initialHeight);
  886. #if DEBUG_KP_MAIN_WINDOW
  887. kdDebug () << "\t\tcreating geometry=" << geometryRect << endl;
  888. #endif
  889. geometryRect = mapToGlobal (geometryRect);
  890. #if DEBUG_KP_MAIN_WINDOW
  891. kdDebug () << "\t\tmap to global=" << geometryRect << endl;
  892. #endif
  893. m_thumbnail->resize (geometryRect.size ());
  894. m_thumbnail->move (geometryRect.topLeft ());
  895. }
  896. }
  897. #if DEBUG_KP_MAIN_WINDOW
  898. kdDebug () << "\t\tshowing thumbnail" << endl;
  899. #endif
  900. m_thumbnail->show ();
  901. #if DEBUG_KP_MAIN_WINDOW
  902. kdDebug () << "\t\tconnecting thumbnail::visibilityChange to destroy slot" << endl;
  903. #endif
  904. connect (m_thumbnail, TQT_SIGNAL (visibilityChanged (bool)),
  905. TQT_TQOBJECT(this), TQT_SLOT (slotDestroyThumbnailIfNotVisible (bool)));
  906. #if DEBUG_KP_MAIN_WINDOW
  907. kdDebug () << "\t\tDONE" << endl;
  908. #endif
  909. }
  910. else
  911. {
  912. #if DEBUG_KP_MAIN_WINDOW
  913. kdDebug () << "\tdestroying thumbnail" << endl;
  914. #endif
  915. if (m_thumbnailSaveConfigTimer && m_thumbnailSaveConfigTimer->isActive ())
  916. {
  917. m_thumbnailSaveConfigTimer->stop ();
  918. slotSaveThumbnailGeometry ();
  919. }
  920. destroyThumbnailView ();
  921. disconnect (m_thumbnail, TQT_SIGNAL (visibilityChanged (bool)),
  922. TQT_TQOBJECT(this), TQT_SLOT (slotDestroyThumbnailIfNotVisible (bool)));
  923. m_thumbnail->deleteLater (); m_thumbnail = 0;
  924. }
  925. }