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.
1152 lines
34 KiB
1152 lines
34 KiB
|
|
/*
|
|
Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#define DEBUG_ZOOM_FLICKER 0
|
|
|
|
#include <kpmainwindow.h>
|
|
#include <kpmainwindow_p.h>
|
|
|
|
#include <tqdatetime.h>
|
|
#include <tqpainter.h>
|
|
#include <tqtimer.h>
|
|
|
|
#include <kactionclasses.h>
|
|
#include <kapplication.h>
|
|
#include <tdeconfig.h>
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kstdaction.h>
|
|
|
|
#include <kpdefs.h>
|
|
#include <kpdocument.h>
|
|
#include <kpthumbnail.h>
|
|
#include <kptool.h>
|
|
#include <kptooltoolbar.h>
|
|
#include <kpunzoomedthumbnailview.h>
|
|
#include <kpviewmanager.h>
|
|
#include <kpviewscrollablecontainer.h>
|
|
#include <kpwidgetmapper.h>
|
|
#include <kpzoomedview.h>
|
|
#include <kpzoomedthumbnailview.h>
|
|
|
|
|
|
// private
|
|
void kpMainWindow::setupViewMenuActions ()
|
|
{
|
|
m_viewMenuDocumentActionsEnabled = false;
|
|
m_thumbnailSaveConfigTimer = 0;
|
|
|
|
|
|
KActionCollection *ac = actionCollection ();
|
|
|
|
/*m_actionFullScreen = KStdAction::fullScreen (0, 0, ac);
|
|
m_actionFullScreen->setEnabled (false);*/
|
|
|
|
|
|
m_actionActualSize = KStdAction::actualSize (TQT_TQOBJECT(this), TQT_SLOT (slotActualSize ()), ac);
|
|
/*m_actionFitToPage = KStdAction::fitToPage (TQT_TQOBJECT(this), TQT_SLOT (slotFitToPage ()), ac);
|
|
m_actionFitToWidth = KStdAction::fitToWidth (TQT_TQOBJECT(this), TQT_SLOT (slotFitToWidth ()), ac);
|
|
m_actionFitToHeight = KStdAction::fitToHeight (TQT_TQOBJECT(this), TQT_SLOT (slotFitToHeight ()), ac);*/
|
|
|
|
|
|
m_actionZoomIn = KStdAction::zoomIn (TQT_TQOBJECT(this), TQT_SLOT (slotZoomIn ()), ac);
|
|
m_actionZoomOut = KStdAction::zoomOut (TQT_TQOBJECT(this), TQT_SLOT (slotZoomOut ()), ac);
|
|
|
|
|
|
m_actionZoom = new KSelectAction (i18n ("&Zoom"), 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotZoom ()), actionCollection (), "view_zoom_to");
|
|
m_actionZoom->setEditable (true);
|
|
|
|
// create the zoom list for the 1st call to zoomTo() below
|
|
m_zoomList.append (10); m_zoomList.append (25); m_zoomList.append (33);
|
|
m_zoomList.append (50); m_zoomList.append (67); m_zoomList.append (75);
|
|
m_zoomList.append (100);
|
|
m_zoomList.append (200); m_zoomList.append (300);
|
|
m_zoomList.append (400); m_zoomList.append (600); m_zoomList.append (800);
|
|
m_zoomList.append (1000); m_zoomList.append (1200); m_zoomList.append (1600);
|
|
|
|
|
|
m_actionShowGrid = new KToggleAction (i18n ("Show &Grid"), CTRL + Key_G,
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotShowGridToggled ()), actionCollection (), "view_show_grid");
|
|
m_actionShowGrid->setCheckedState (i18n ("Hide &Grid"));
|
|
|
|
|
|
// TODO: This doesn't work when the thumbnail has focus.
|
|
// Testcase: Press CTRL+H twice on a fresh KolourPaint.
|
|
// The second CTRL+H doesn't close the thumbnail.
|
|
m_actionShowThumbnail = new KToggleAction (i18n ("Show T&humbnail"), CTRL + Key_H,
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotShowThumbnailToggled ()), actionCollection (), "view_show_thumbnail");
|
|
m_actionShowThumbnail->setCheckedState (i18n ("Hide T&humbnail"));
|
|
|
|
// Please do not use setCheckedState() here - it wouldn't make sense
|
|
m_actionZoomedThumbnail = new KToggleAction (i18n ("Zoo&med Thumbnail Mode"), 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotZoomedThumbnailToggled ()), actionCollection (), "view_zoomed_thumbnail");
|
|
|
|
// For consistency with the above action, don't use setCheckedState()
|
|
//
|
|
// Also, don't use "Show Thumbnail Rectangle" because if entire doc
|
|
// can be seen in scrollView, checking option won't "Show" anything
|
|
// since rect _surrounds_ entire doc (hence, won't be rendered).
|
|
d->m_actionShowThumbnailRectangle = new KToggleAction (
|
|
i18n ("Enable Thumbnail &Rectangle"),
|
|
0,
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotThumbnailShowRectangleToggled ()),
|
|
actionCollection (), "view_show_thumbnail_rectangle");
|
|
|
|
|
|
enableViewMenuDocumentActions (false);
|
|
}
|
|
|
|
// private
|
|
bool kpMainWindow::viewMenuDocumentActionsEnabled () const
|
|
{
|
|
return m_viewMenuDocumentActionsEnabled;
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::enableViewMenuDocumentActions (bool enable)
|
|
{
|
|
m_viewMenuDocumentActionsEnabled = enable;
|
|
|
|
|
|
m_actionActualSize->setEnabled (enable);
|
|
/*m_actionFitToPage->setEnabled (enable);
|
|
m_actionFitToWidth->setEnabled (enable);
|
|
m_actionFitToHeight->setEnabled (enable);*/
|
|
|
|
m_actionZoomIn->setEnabled (enable);
|
|
m_actionZoomOut->setEnabled (enable);
|
|
|
|
m_actionZoom->setEnabled (enable);
|
|
|
|
actionShowGridUpdate ();
|
|
|
|
m_actionShowThumbnail->setEnabled (enable);
|
|
enableThumbnailOptionActions (enable);
|
|
|
|
|
|
// TODO: for the time being, assume that we start at zoom 100%
|
|
// with no grid
|
|
|
|
// This function is only called when a new document is created
|
|
// or an existing document is closed. So the following will
|
|
// always be correct:
|
|
|
|
zoomTo (100);
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::actionShowGridUpdate ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::actionShowGridUpdate()" << endl;
|
|
#endif
|
|
const bool enable = (viewMenuDocumentActionsEnabled () &&
|
|
m_mainView && m_mainView->canShowGrid ());
|
|
|
|
m_actionShowGrid->setEnabled (enable);
|
|
m_actionShowGrid->setChecked (enable && m_configShowGrid);
|
|
}
|
|
|
|
|
|
// private
|
|
void kpMainWindow::sendZoomListToActionZoom ()
|
|
{
|
|
TQStringList items;
|
|
|
|
const TQValueVector <int>::ConstIterator zoomListEnd (m_zoomList.end ());
|
|
for (TQValueVector <int>::ConstIterator it = m_zoomList.begin ();
|
|
it != zoomListEnd;
|
|
it++)
|
|
{
|
|
items << zoomLevelToString (*it);
|
|
}
|
|
|
|
// Work around a KDE bug - KSelectAction::setItems() enables the action.
|
|
// David Faure said it won't be fixed because it's a feature used by
|
|
// KRecentFilesAction.
|
|
bool e = m_actionZoom->isEnabled ();
|
|
m_actionZoom->setItems (items);
|
|
if (e != m_actionZoom->isEnabled ())
|
|
m_actionZoom->setEnabled (e);
|
|
}
|
|
|
|
// private
|
|
int kpMainWindow::zoomLevelFromString (const TQString &string)
|
|
{
|
|
// loop until not digit
|
|
int i;
|
|
for (i = 0; i < (int) string.length () && string.at (i).isDigit (); i++)
|
|
;
|
|
|
|
// convert zoom level to number
|
|
bool ok = false;
|
|
int zoomLevel = string.left (i).toInt (&ok);
|
|
|
|
if (!ok || zoomLevel <= 0 || zoomLevel > 3200)
|
|
return 0; // error
|
|
else
|
|
return zoomLevel;
|
|
}
|
|
|
|
// private
|
|
TQString kpMainWindow::zoomLevelToString (int zoomLevel)
|
|
{
|
|
return i18n ("%1%").arg (zoomLevel);
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor)
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::zoomTo (" << zoomLevel << ")" << endl;
|
|
#endif
|
|
|
|
if (zoomLevel <= 0)
|
|
zoomLevel = m_mainView ? m_mainView->zoomLevelX () : 100;
|
|
|
|
// mute point since the thumbnail suffers from this too
|
|
#if 0
|
|
else if (m_mainView && m_mainView->zoomLevelX () % 100 == 0 && zoomLevel % 100)
|
|
{
|
|
if (KMessageBox::warningContinueCancel (this,
|
|
i18n ("Setting the zoom level to a value that is not a multiple of 100% "
|
|
"results in imprecise editing and redraw glitches.\n"
|
|
"Do you really want to set to zoom level to %1%?")
|
|
.arg (zoomLevel),
|
|
TQString()/*caption*/,
|
|
i18n ("Set Zoom Level to %1%").arg (zoomLevel),
|
|
"DoNotAskAgain_ZoomLevelNotMultipleOf100") != KMessageBox::Continue)
|
|
{
|
|
zoomLevel = m_mainView->zoomLevelX ();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int index = 0;
|
|
TQValueVector <int>::Iterator it = m_zoomList.begin ();
|
|
|
|
while (index < (int) m_zoomList.count () && zoomLevel > *it)
|
|
it++, index++;
|
|
|
|
if (zoomLevel != *it)
|
|
m_zoomList.insert (it, zoomLevel);
|
|
|
|
sendZoomListToActionZoom ();
|
|
m_actionZoom->setCurrentItem (index);
|
|
|
|
|
|
if (viewMenuDocumentActionsEnabled ())
|
|
{
|
|
m_actionActualSize->setEnabled (zoomLevel != 100);
|
|
|
|
m_actionZoomIn->setEnabled (m_actionZoom->currentItem () < (int) m_zoomList.count () - 1);
|
|
m_actionZoomOut->setEnabled (m_actionZoom->currentItem () > 0);
|
|
}
|
|
|
|
|
|
if (m_viewManager)
|
|
m_viewManager->setQueueUpdates ();
|
|
|
|
|
|
if (m_scrollView)
|
|
{
|
|
m_scrollView->setUpdatesEnabled (false);
|
|
if (m_scrollView->viewport ())
|
|
m_scrollView->viewport ()->setUpdatesEnabled (false);
|
|
}
|
|
|
|
if (m_mainView)
|
|
{
|
|
m_mainView->setUpdatesEnabled (false);
|
|
|
|
if (m_scrollView && m_scrollView->viewport ())
|
|
{
|
|
// Ordinary flicker is better than the whole view moving
|
|
TQPainter p (m_mainView);
|
|
p.fillRect (m_mainView->rect (),
|
|
m_scrollView->viewport ()->colorGroup ().background ());
|
|
}
|
|
}
|
|
|
|
|
|
if (m_scrollView && m_mainView)
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW && 1
|
|
kdDebug () << "\tscrollView contentsX=" << m_scrollView->contentsX ()
|
|
<< " contentsY=" << m_scrollView->contentsY ()
|
|
<< " contentsWidth=" << m_scrollView->contentsWidth ()
|
|
<< " contentsHeight=" << m_scrollView->contentsHeight ()
|
|
<< " visibleWidth=" << m_scrollView->visibleWidth ()
|
|
<< " visibleHeight=" << m_scrollView->visibleHeight ()
|
|
<< " oldZoomX=" << m_mainView->zoomLevelX ()
|
|
<< " oldZoomY=" << m_mainView->zoomLevelY ()
|
|
<< " newZoom=" << zoomLevel
|
|
<< " mainViewX=" << m_scrollView->childX (m_mainView)
|
|
<< " mainViewY=" << m_scrollView->childY (m_mainView)
|
|
<< endl;
|
|
#endif
|
|
|
|
// TODO: when changing from no scrollbars to scrollbars, TQt lies about
|
|
// visibleWidth() & visibleHeight() (doesn't take into account the
|
|
// space taken by the would-be scrollbars) until it updates the
|
|
// scrollview; hence the centring is off by about 5-10 pixels.
|
|
|
|
// TODO: use visibleRect() for greater accuracy?
|
|
|
|
int viewX, viewY;
|
|
|
|
bool targetDocAvail = false;
|
|
double targetDocX, targetDocY;
|
|
|
|
if (centerUnderCursor &&
|
|
m_viewManager && m_viewManager->viewUnderCursor ())
|
|
{
|
|
kpView *const vuc = m_viewManager->viewUnderCursor ();
|
|
TQPoint viewPoint = vuc->mouseViewPoint ();
|
|
|
|
// vuc->transformViewToDoc() returns TQPoint which only has int
|
|
// accuracy so we do X and Y manually.
|
|
targetDocX = vuc->transformViewToDocX (viewPoint.x ());
|
|
targetDocY = vuc->transformViewToDocY (viewPoint.y ());
|
|
targetDocAvail = true;
|
|
|
|
if (vuc != m_mainView)
|
|
viewPoint = vuc->transformViewToOtherView (viewPoint, m_mainView);
|
|
|
|
viewX = viewPoint.x ();
|
|
viewY = viewPoint.y ();
|
|
}
|
|
else
|
|
{
|
|
viewX = m_scrollView->contentsX () +
|
|
TQMIN (m_mainView->width (),
|
|
m_scrollView->visibleWidth ()) / 2;
|
|
viewY = m_scrollView->contentsY () +
|
|
TQMIN (m_mainView->height (),
|
|
m_scrollView->visibleHeight ()) / 2;
|
|
}
|
|
|
|
int newCenterX = viewX * zoomLevel / m_mainView->zoomLevelX ();
|
|
int newCenterY = viewY * zoomLevel / m_mainView->zoomLevelY ();
|
|
|
|
m_mainView->setZoomLevel (zoomLevel, zoomLevel);
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just setZoomLevel" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW && 1
|
|
kdDebug () << "\tvisibleWidth=" << m_scrollView->visibleWidth ()
|
|
<< " visibleHeight=" << m_scrollView->visibleHeight ()
|
|
<< endl;
|
|
kdDebug () << "\tnewCenterX=" << newCenterX
|
|
<< " newCenterY=" << newCenterY << endl;
|
|
#endif
|
|
|
|
m_scrollView->center (newCenterX, newCenterY);
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just centred" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 2000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
if (centerUnderCursor &&
|
|
targetDocAvail &&
|
|
m_viewManager && m_viewManager->viewUnderCursor ())
|
|
{
|
|
kpView *const vuc = m_viewManager->viewUnderCursor ();
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\tcenterUnderCursor: reposition cursor; viewUnderCursor="
|
|
<< vuc->name () << endl;
|
|
#endif
|
|
|
|
const double viewX = vuc->transformDocToViewX (targetDocX);
|
|
const double viewY = vuc->transformDocToViewY (targetDocY);
|
|
// Rounding error from zooming in and out :(
|
|
// TODO: do everything in terms of tool doc points in type "double".
|
|
const TQPoint viewPoint ((int) viewX, (int) viewY);
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")"
|
|
<< " viewUnderCursor: (" << viewX << "," << viewY << ")"
|
|
<< endl;
|
|
#endif
|
|
|
|
if (vuc->clipRegion ().contains (viewPoint))
|
|
{
|
|
const TQPoint globalPoint =
|
|
kpWidgetMapper::toGlobal (vuc, viewPoint);
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tglobalPoint=" << globalPoint << endl;
|
|
#endif
|
|
|
|
// TODO: Determine some sane cursor flashing indication -
|
|
// cursor movement is convenient but not conventional.
|
|
//
|
|
// Major problem: if using TQApplication::setOverrideCursor()
|
|
// and in some stage of flash and window quits.
|
|
//
|
|
// Or if using kpView::setCursor() and change tool.
|
|
TQCursor::setPos (globalPoint);
|
|
}
|
|
// e.g. Zoom to 200%, scroll mainView to bottom-right.
|
|
// Unzoomed Thumbnail shows top-left portion of bottom-right of
|
|
// mainView.
|
|
//
|
|
// Aim cursor at bottom-right of thumbnail and zoom out with
|
|
// CTRL+Wheel.
|
|
//
|
|
// If mainView is now small enough to largely not need scrollbars,
|
|
// Unzoomed Thumbnail scrolls to show _top-left_ portion
|
|
// _of top-left_ of mainView.
|
|
//
|
|
// Unzoomed Thumbnail no longer contains the point we zoomed out
|
|
// on top of.
|
|
else
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\twon't move cursor - would get outside view"
|
|
<< endl;
|
|
#endif
|
|
|
|
// TODO: Sane cursor flashing indication that indicates
|
|
// that the normal cursor movement didn't happen.
|
|
}
|
|
}
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW && 1
|
|
kdDebug () << "\t\tcheck (contentsX=" << m_scrollView->contentsX ()
|
|
<< ",contentsY=" << m_scrollView->contentsY ()
|
|
<< ")" << endl;
|
|
#endif
|
|
}
|
|
|
|
if (m_mainView)
|
|
{
|
|
actionShowGridUpdate ();
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: updated grid action" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
|
|
updateMainViewGrid ();
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just updated grid" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
|
|
// Since Zoom Level KSelectAction on ToolBar grabs focus after changing
|
|
// Zoom, switch back to the Main View.
|
|
// TODO: back to the last view
|
|
m_mainView->setFocus ();
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just set focus to mainview" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
#if 1
|
|
// The view magnified and moved beneath the cursor
|
|
if (tool ())
|
|
tool ()->somethingBelowTheCursorChanged ();
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: signalled something below cursor" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// HACK: make sure all of TQt's update() calls trigger
|
|
// kpView::paintEvent() _now_ so that they can be queued by us
|
|
// (until kpViewManager::restoreQueueUpdates()) to reduce flicker
|
|
// caused mainly by m_scrollView->center()
|
|
//
|
|
// TODO: remove flicker completely
|
|
//TQTimer::singleShot (0, TQT_TQOBJECT(this), TQT_SLOT (finishZoomTo ()));
|
|
|
|
// Later: I don't think there is an update() that needs to be queued
|
|
// - let's reduce latency instead.
|
|
finishZoomTo ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::finishZoomTo ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW && 1
|
|
kdDebug () << "\tkpMainWindow::finishZoomTo enter" << endl;
|
|
#endif
|
|
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: inside finishZoomTo" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 2000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
// TODO: setUpdatesEnabled() should really return to old value
|
|
// - not neccessarily "true"
|
|
|
|
if (m_mainView)
|
|
{
|
|
m_mainView->setUpdatesEnabled (true);
|
|
m_mainView->update ();
|
|
}
|
|
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just updated mainView" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
if (m_scrollView)
|
|
{
|
|
if (m_scrollView->viewport ())
|
|
{
|
|
m_scrollView->viewport ()->setUpdatesEnabled (true);
|
|
m_scrollView->viewport ()->update ();
|
|
}
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just updated scrollView::viewport()" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
m_scrollView->setUpdatesEnabled (true);
|
|
m_scrollView->update ();
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: just updated scrollView" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
if (m_viewManager && m_viewManager->queueUpdates ()/*just in case*/)
|
|
m_viewManager->restoreQueueUpdates ();
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: restored vm queued updates" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
|
|
setStatusBarZoom (m_mainView ? m_mainView->zoomLevelX () : 0);
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW && 1
|
|
kdDebug () << "\tkpMainWindow::finishZoomTo done" << endl;
|
|
#endif
|
|
|
|
#if DEBUG_ZOOM_FLICKER
|
|
{
|
|
kdDebug () << "FLICKER: finishZoomTo done" << endl;
|
|
TQTime timer; timer.start ();
|
|
while (timer.elapsed () < 1000)
|
|
;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// private slot
|
|
void kpMainWindow::slotActualSize ()
|
|
{
|
|
zoomTo (100);
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotFitToPage ()
|
|
{
|
|
if (!m_scrollView || !m_document)
|
|
return;
|
|
|
|
// doc_width * zoom / 100 <= view_width &&
|
|
// doc_height * zoom / 100 <= view_height &&
|
|
// 1 <= zoom <= 3200
|
|
|
|
zoomTo (TQMIN (3200, TQMAX (1, TQMIN (m_scrollView->visibleWidth () * 100 / m_document->width (),
|
|
m_scrollView->visibleHeight () * 100 / m_document->height ()))));
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotFitToWidth ()
|
|
{
|
|
if (!m_scrollView || !m_document)
|
|
return;
|
|
|
|
// doc_width * zoom / 100 <= view_width &&
|
|
// 1 <= zoom <= 3200
|
|
|
|
zoomTo (TQMIN (3200, TQMAX (1, m_scrollView->visibleWidth () * 100 / m_document->width ())));
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotFitToHeight ()
|
|
{
|
|
if (!m_scrollView || !m_document)
|
|
return;
|
|
|
|
// doc_height * zoom / 100 <= view_height &&
|
|
// 1 <= zoom <= 3200
|
|
|
|
zoomTo (TQMIN (3200, TQMAX (1, m_scrollView->visibleHeight () * 100 / m_document->height ())));
|
|
}
|
|
|
|
|
|
// public
|
|
void kpMainWindow::zoomIn (bool centerUnderCursor)
|
|
{
|
|
const int targetItem = m_actionZoom->currentItem () + 1;
|
|
|
|
if (targetItem >= (int) m_zoomList.count ())
|
|
return;
|
|
|
|
m_actionZoom->setCurrentItem (targetItem);
|
|
zoomAccordingToZoomAction (centerUnderCursor);
|
|
}
|
|
|
|
// public
|
|
void kpMainWindow::zoomOut (bool centerUnderCursor)
|
|
{
|
|
const int targetItem = m_actionZoom->currentItem () - 1;
|
|
|
|
if (targetItem < 0)
|
|
return;
|
|
|
|
m_actionZoom->setCurrentItem (targetItem);
|
|
zoomAccordingToZoomAction (centerUnderCursor);
|
|
}
|
|
|
|
|
|
// public slot
|
|
void kpMainWindow::slotZoomIn ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotZoomIn ()" << endl;
|
|
#endif
|
|
|
|
zoomIn (false/*don't center under cursor*/);
|
|
}
|
|
|
|
// public slot
|
|
void kpMainWindow::slotZoomOut ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotZoomOut ()" << endl;
|
|
#endif
|
|
|
|
zoomOut (false/*don't center under cursor*/);
|
|
}
|
|
|
|
|
|
// public
|
|
void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor)
|
|
{
|
|
zoomTo (zoomLevelFromString (m_actionZoom->currentText ()),
|
|
centerUnderCursor);
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotZoom ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotZoom () index=" << m_actionZoom->currentItem ()
|
|
<< " text='" << m_actionZoom->currentText () << "'" << endl;
|
|
#endif
|
|
zoomAccordingToZoomAction (false/*don't center under cursor*/);
|
|
}
|
|
|
|
|
|
// private slot
|
|
void kpMainWindow::slotShowGridToggled ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotActionShowGridToggled()" << endl;
|
|
#endif
|
|
|
|
updateMainViewGrid ();
|
|
|
|
|
|
TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
|
|
TDEConfigBase *cfg = cfgGroupSaver.config ();
|
|
|
|
cfg->writeEntry (kpSettingShowGrid, m_configShowGrid = m_actionShowGrid->isChecked ());
|
|
cfg->sync ();
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::updateMainViewGrid ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::updateMainViewGrid ()" << endl;
|
|
#endif
|
|
|
|
if (m_mainView)
|
|
m_mainView->showGrid (m_actionShowGrid->isChecked ());
|
|
}
|
|
|
|
|
|
// private
|
|
TQRect kpMainWindow::mapToGlobal (const TQRect &rect) const
|
|
{
|
|
return kpWidgetMapper::toGlobal (this, rect);
|
|
}
|
|
|
|
// private
|
|
TQRect kpMainWindow::mapFromGlobal (const TQRect &rect) const
|
|
{
|
|
return kpWidgetMapper::fromGlobal (this, rect);
|
|
}
|
|
|
|
|
|
// public slot
|
|
void kpMainWindow::slotDestroyThumbnailIfNotVisible (bool tnIsVisible)
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotDestroyThumbnailIfNotVisible(isVisible="
|
|
<< tnIsVisible
|
|
<< ")"
|
|
<< endl;
|
|
#endif
|
|
|
|
if (!tnIsVisible)
|
|
{
|
|
slotDestroyThumbnailInitatedByUser ();
|
|
}
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotDestroyThumbnail ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotDestroyThumbnail()" << endl;
|
|
#endif
|
|
|
|
m_actionShowThumbnail->setChecked (false);
|
|
enableThumbnailOptionActions (false);
|
|
updateThumbnail ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotDestroyThumbnailInitatedByUser ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()" << endl;
|
|
#endif
|
|
|
|
m_actionShowThumbnail->setChecked (false);
|
|
slotShowThumbnailToggled ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotCreateThumbnail ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotCreateThumbnail()" << endl;
|
|
#endif
|
|
|
|
m_actionShowThumbnail->setChecked (true);
|
|
enableThumbnailOptionActions (true);
|
|
updateThumbnail ();
|
|
}
|
|
|
|
// public
|
|
void kpMainWindow::notifyThumbnailGeometryChanged ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::notifyThumbnailGeometryChanged()" << endl;
|
|
#endif
|
|
|
|
if (!m_thumbnailSaveConfigTimer)
|
|
{
|
|
m_thumbnailSaveConfigTimer = new TQTimer (this);
|
|
connect (m_thumbnailSaveConfigTimer, TQT_SIGNAL (timeout ()),
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotSaveThumbnailGeometry ()));
|
|
}
|
|
|
|
m_thumbnailSaveConfigTimer->start (500/*msec*/, true/*single shot*/);
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotSaveThumbnailGeometry ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::saveThumbnailGeometry()" << endl;
|
|
#endif
|
|
|
|
if (!m_thumbnail)
|
|
return;
|
|
|
|
TQRect rect (m_thumbnail->x (), m_thumbnail->y (),
|
|
m_thumbnail->width (), m_thumbnail->height ());
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\tthumbnail relative geometry=" << rect << endl;
|
|
#endif
|
|
|
|
m_configThumbnailGeometry = mapFromGlobal (rect);
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\tCONFIG: saving thumbnail geometry "
|
|
<< m_configThumbnailGeometry
|
|
<< endl;
|
|
#endif
|
|
|
|
TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
|
|
TDEConfigBase *cfg = cfgGroupSaver.config ();
|
|
|
|
cfg->writeEntry (kpSettingThumbnailGeometry, m_configThumbnailGeometry);
|
|
cfg->sync ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotShowThumbnailToggled ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotShowThumbnailToggled()" << endl;
|
|
#endif
|
|
|
|
m_configThumbnailShown = m_actionShowThumbnail->isChecked ();
|
|
|
|
TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
|
|
TDEConfigBase *cfg = cfgGroupSaver.config ();
|
|
|
|
cfg->writeEntry (kpSettingThumbnailShown, m_configThumbnailShown);
|
|
cfg->sync ();
|
|
|
|
|
|
enableThumbnailOptionActions (m_actionShowThumbnail->isChecked ());
|
|
updateThumbnail ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::updateThumbnailZoomed ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::updateThumbnailZoomed() zoomed="
|
|
<< m_actionZoomedThumbnail->isChecked () << endl;
|
|
#endif
|
|
|
|
if (!m_thumbnailView)
|
|
return;
|
|
|
|
destroyThumbnailView ();
|
|
createThumbnailView ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotZoomedThumbnailToggled ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotZoomedThumbnailToggled()" << endl;
|
|
#endif
|
|
|
|
m_configZoomedThumbnail = m_actionZoomedThumbnail->isChecked ();
|
|
|
|
TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
|
|
TDEConfigBase *cfg = cfgGroupSaver.config ();
|
|
|
|
cfg->writeEntry (kpSettingThumbnailZoomed, m_configZoomedThumbnail);
|
|
cfg->sync ();
|
|
|
|
|
|
updateThumbnailZoomed ();
|
|
}
|
|
|
|
// private slot
|
|
void kpMainWindow::slotThumbnailShowRectangleToggled ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::slotThumbnailShowRectangleToggled()" << endl;
|
|
#endif
|
|
|
|
d->m_configThumbnailShowRectangle = d->m_actionShowThumbnailRectangle->isChecked ();
|
|
|
|
TDEConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
|
|
TDEConfigBase *cfg = cfgGroupSaver.config ();
|
|
|
|
cfg->writeEntry (kpSettingThumbnailShowRectangle, d->m_configThumbnailShowRectangle);
|
|
cfg->sync ();
|
|
|
|
|
|
if (m_thumbnailView)
|
|
{
|
|
m_thumbnailView->showBuddyViewScrollableContainerRectangle (
|
|
d->m_actionShowThumbnailRectangle->isChecked ());
|
|
}
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::enableViewZoomedThumbnail (bool enable)
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::enableSettingsViewZoomedThumbnail()" << endl;
|
|
#endif
|
|
|
|
m_actionZoomedThumbnail->setEnabled (enable &&
|
|
m_actionShowThumbnail->isChecked ());
|
|
|
|
// Note: Don't uncheck if disabled - being able to see the zoomed state
|
|
// before turning on the thumbnail can be useful.
|
|
m_actionZoomedThumbnail->setChecked (m_configZoomedThumbnail);
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::enableViewShowThumbnailRectangle (bool enable)
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::enableViewShowThumbnailRectangle()" << endl;
|
|
#endif
|
|
|
|
d->m_actionShowThumbnailRectangle->setEnabled (enable &&
|
|
m_actionShowThumbnail->isChecked ());
|
|
|
|
// Note: Don't uncheck if disabled for consistency with
|
|
// enableViewZoomedThumbnail()
|
|
d->m_actionShowThumbnailRectangle->setChecked (
|
|
d->m_configThumbnailShowRectangle);
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::enableThumbnailOptionActions (bool enable)
|
|
{
|
|
enableViewZoomedThumbnail (enable);
|
|
enableViewShowThumbnailRectangle (enable);
|
|
}
|
|
|
|
|
|
// private
|
|
void kpMainWindow::createThumbnailView ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tcreating new kpView:" << endl;
|
|
#endif
|
|
|
|
if (m_thumbnailView)
|
|
{
|
|
kdDebug () << "kpMainWindow::createThumbnailView() had to destroy view" << endl;
|
|
destroyThumbnailView ();
|
|
}
|
|
|
|
if (m_actionZoomedThumbnail->isChecked ())
|
|
{
|
|
m_thumbnailView = new kpZoomedThumbnailView (
|
|
m_document, m_toolToolBar, m_viewManager,
|
|
m_mainView,
|
|
0/*scrollableContainer*/,
|
|
m_thumbnail, "thumbnailView");
|
|
}
|
|
else
|
|
{
|
|
m_thumbnailView = new kpUnzoomedThumbnailView (
|
|
m_document, m_toolToolBar, m_viewManager,
|
|
m_mainView,
|
|
0/*scrollableContainer*/,
|
|
m_thumbnail, "thumbnailView");
|
|
|
|
}
|
|
|
|
m_thumbnailView->showBuddyViewScrollableContainerRectangle (
|
|
d->m_actionShowThumbnailRectangle->isChecked ());
|
|
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tgive kpThumbnail the kpView:" << endl;
|
|
#endif
|
|
if (m_thumbnail)
|
|
m_thumbnail->setView (m_thumbnailView);
|
|
else
|
|
kdError () << "kpMainWindow::createThumbnailView() no thumbnail" << endl;
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tregistering the kpView:" << endl;
|
|
#endif
|
|
if (m_viewManager)
|
|
m_viewManager->registerView (m_thumbnailView);
|
|
}
|
|
|
|
// private
|
|
void kpMainWindow::destroyThumbnailView ()
|
|
{
|
|
if (!m_thumbnailView)
|
|
return;
|
|
|
|
if (m_viewManager)
|
|
m_viewManager->unregisterView (m_thumbnailView);
|
|
|
|
if (m_thumbnail)
|
|
m_thumbnail->setView (0);
|
|
|
|
m_thumbnailView->deleteLater (); m_thumbnailView = 0;
|
|
}
|
|
|
|
|
|
// private
|
|
void kpMainWindow::updateThumbnail ()
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "kpMainWindow::updateThumbnail()" << endl;
|
|
#endif
|
|
bool enable = m_actionShowThumbnail->isChecked ();
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\tthumbnail="
|
|
<< bool (m_thumbnail)
|
|
<< " action_isChecked="
|
|
<< enable
|
|
<< endl;
|
|
#endif
|
|
|
|
if (bool (m_thumbnail) == enable)
|
|
return;
|
|
|
|
if (!m_thumbnail)
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\tcreating thumbnail" << endl;
|
|
#endif
|
|
|
|
// Read last saved geometry before creating thumbnail & friends
|
|
// in case they call notifyThumbnailGeometryChanged()
|
|
TQRect thumbnailGeometry = m_configThumbnailGeometry;
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tlast used geometry=" << thumbnailGeometry << endl;
|
|
#endif
|
|
|
|
m_thumbnail = new kpThumbnail (this, "thumbnail");
|
|
|
|
createThumbnailView ();
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tmoving thumbnail to right place" << endl;
|
|
#endif
|
|
if (!thumbnailGeometry.isEmpty () &&
|
|
TQRect (0, 0, width (), height ()).intersects (thumbnailGeometry))
|
|
{
|
|
const TQRect geometry = mapToGlobal (thumbnailGeometry);
|
|
m_thumbnail->resize (geometry.size ());
|
|
m_thumbnail->move (geometry.topLeft ());
|
|
}
|
|
else
|
|
{
|
|
if (m_scrollView)
|
|
{
|
|
const int margin = 20;
|
|
const int initialWidth = 160, initialHeight = 120;
|
|
|
|
TQRect geometryRect (width () - initialWidth - margin * 2,
|
|
m_scrollView->y () + margin,
|
|
initialWidth,
|
|
initialHeight);
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tcreating geometry=" << geometryRect << endl;
|
|
#endif
|
|
|
|
geometryRect = mapToGlobal (geometryRect);
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tmap to global=" << geometryRect << endl;
|
|
#endif
|
|
m_thumbnail->resize (geometryRect.size ());
|
|
m_thumbnail->move (geometryRect.topLeft ());
|
|
}
|
|
}
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tshowing thumbnail" << endl;
|
|
#endif
|
|
m_thumbnail->show ();
|
|
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tconnecting thumbnail::visibilityChange to destroy slot" << endl;
|
|
#endif
|
|
connect (m_thumbnail, TQT_SIGNAL (visibilityChanged (bool)),
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotDestroyThumbnailIfNotVisible (bool)));
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\t\tDONE" << endl;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if DEBUG_KP_MAIN_WINDOW
|
|
kdDebug () << "\tdestroying thumbnail" << endl;
|
|
#endif
|
|
|
|
if (m_thumbnailSaveConfigTimer && m_thumbnailSaveConfigTimer->isActive ())
|
|
{
|
|
m_thumbnailSaveConfigTimer->stop ();
|
|
slotSaveThumbnailGeometry ();
|
|
}
|
|
|
|
|
|
destroyThumbnailView ();
|
|
|
|
|
|
disconnect (m_thumbnail, TQT_SIGNAL (visibilityChanged (bool)),
|
|
TQT_TQOBJECT(this), TQT_SLOT (slotDestroyThumbnailIfNotVisible (bool)));
|
|
|
|
m_thumbnail->deleteLater (); m_thumbnail = 0;
|
|
}
|
|
}
|