2004-09-26 23:39:39 +00:00
/***************************************************************************
2005-02-18 18:24:45 +00:00
* Copyright ( C ) 2004 - 2005 by Enrico Ros < eros . kde @ email . it > *
2013-03-14 22:09:07 +00:00
* Copyright ( C ) 2004 - 2006 by Albert Astals Cid < aacid @ kde . org > *
2017-11-16 08:57:58 +00:00
* Copyright ( C ) 2017 Klarälvdalens Datakonsult AB , a KDAB Group *
* company , info @ kdab . com . Work sponsored by the *
* LiMux project of the city of Munich *
2004-09-27 21:36:25 +00:00
* *
2005-01-02 14:29:37 +00:00
* With portions of code from kpdf / kpdf_pagewidget . cc by : *
2004-09-27 21:36:25 +00:00
* Copyright ( C ) 2002 by Wilco Greven < greven @ kde . org > *
* Copyright ( C ) 2003 by Christophe Devriese *
* < Christophe . Devriese @ student . kuleuven . ac . be > *
* Copyright ( C ) 2003 by Laurent Montel < montel @ kde . org > *
* Copyright ( C ) 2003 by Dirk Mueller < mueller @ kde . org > *
* Copyright ( C ) 2004 by James Ots < kde @ jamesots . com > *
2011-10-12 13:50:56 +00:00
* Copyright ( C ) 2011 by Jiri Baum - NICTA < jiri @ baum . com . au > *
2004-09-26 23:39:39 +00:00
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-04-19 18:30:20 +00:00
# include "pageview.h"
2005-01-02 14:55:14 +00:00
// qt/kde includes
2020-07-08 11:54:37 +00:00
# include <QApplication>
# include <QClipboard>
# include <QCursor>
2016-07-24 20:31:34 +00:00
# include <QDesktopServices>
2020-07-08 11:54:37 +00:00
# include <QDesktopWidget>
2019-09-21 19:08:47 +00:00
# include <QElapsedTimer>
2020-07-08 11:54:37 +00:00
# include <QEvent>
2016-10-15 13:22:35 +00:00
# include <QGestureEvent>
2020-07-08 11:54:37 +00:00
# include <QImage>
2014-09-28 10:44:33 +00:00
# include <QInputDialog>
2020-07-08 11:54:37 +00:00
# include <QLoggingCategory>
2014-10-08 11:48:01 +00:00
# include <QMenu>
2016-07-17 00:28:57 +00:00
# include <QMimeData>
2019-09-21 19:08:47 +00:00
# include <QMimeDatabase>
# include <QPainter>
2020-07-08 11:54:37 +00:00
# include <QScrollBar>
2019-11-15 16:08:25 +00:00
# include <QScroller>
# include <QScrollerProperties>
2020-07-08 11:54:37 +00:00
# include <QSet>
# include <QTimer>
# include <QToolTip>
2006-10-29 13:17:19 +00:00
2020-07-08 11:54:37 +00:00
# include <KActionCollection>
# include <KActionMenu>
2020-09-11 21:19:36 +00:00
# include <KConfigWatcher>
2015-01-29 20:48:47 +00:00
# include <KLocalizedString>
2020-07-08 11:54:37 +00:00
# include <KMessageBox>
# include <KRun>
# include <KSelectAction>
# include <KStandardAction>
# include <KStringHandler>
# include <KToggleAction>
# include <KToolInvocation>
# include <KUriFilter>
# include <QAction>
2018-08-31 09:23:45 +00:00
# include <QDebug>
2014-10-06 06:31:17 +00:00
# include <QIcon>
2006-06-05 15:47:35 +00:00
2005-01-02 14:55:14 +00:00
// system includes
2020-03-08 17:02:04 +00:00
# include <array>
2004-09-26 23:39:39 +00:00
# include <math.h>
2004-10-06 00:05:49 +00:00
# include <stdlib.h>
2004-09-26 23:39:39 +00:00
2005-01-02 14:55:14 +00:00
// local includes
2006-12-30 12:40:54 +00:00
# include "annotationpopup.h"
2007-05-06 15:10:16 +00:00
# include "annotwindow.h"
2006-08-08 15:31:13 +00:00
# include "core/annotations.h"
2014-09-11 19:12:27 +00:00
# include "debug_ui.h"
2007-02-25 00:07:59 +00:00
# include "formwidgets.h"
2007-12-24 00:54:21 +00:00
# include "guiutils.h"
2006-12-30 12:40:54 +00:00
# include "okmenutitle.h"
2005-01-27 17:31:07 +00:00
# include "pagepainter.h"
2005-03-04 23:06:24 +00:00
# include "pageviewannotator.h"
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
# include "pageviewmouseannotation.h"
2004-10-20 16:41:13 +00:00
# include "pageviewutils.h"
2013-02-24 21:58:53 +00:00
# include "priorities.h"
Replace ToolAction by ToggleActionMenu
Summary:
This replaces ToolAction by a near-drop-in replacement named ToggleActionMenu. The new annotation toolbar already uses this (D15580).
Unlike ToolAction, ToggleActionMenu inherits from KActionMenu to be more flexible.
* Menu can be set from outside, not hard coded.
* Default action for toolbar button is controllable from outside. (Theoretically, the button could trigger //anything// now.)
* KActionMenu instead of KSelectAction:
- Pluggable in other menus, thus called “Menu”.
- Doesn’t make the actions exclusive, so //any// actions can be added to the menu.
* ImplicitDefaultAction mode can choose the default action of the toolbar buttons automatically, by looking for the first checked action in the menu.
Toolbar buttons use the default action //of// this menu, not this menu itself as action.
Because the default action is configurable now, D21622 and D21635 (where we tried to fine-tune ToolAction) become obsolete.
Screenshot:
Everything like before, here with mouse_selecttool added to Tools menu to show submenu capability.
{F6884228}
Test Plan:
ToolAction replacement and ImplicitDefaultAction mode:
* Open Okular and look at toolbar button -> has correct tool selected.
* Open a document.
* Look at toolbar button menu -> Correct menu entries (like before, with ToolAction).
* Select some selection tools through shortcuts and toolbar button -> behaves correctly.
Usage as submenu:
* Add ToggleActionMenu ("mouse_selecttool") to menubar (..../kxmlgui5/okular/part.rc) -> Submenu looks correctly, has no checkbox attached and so on...
Toolbar buttons:
* Add diverse other actions to the menu -> still works as before.
* Add actions when toolbar buttons are already created -> actions are added to existing buttons.
* setDefaultAction() to some completely unrelated action. -> ToggleActionMenu does not get confused.
Reviewers: simgunz
Reviewed By: simgunz
Subscribers: aacid, ngraham, simgunz, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D21971
2020-02-01 18:54:18 +00:00
# include "toggleactionmenu.h"
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-03-05 02:13:09 +00:00
# include "tts.h"
2014-11-08 04:33:23 +00:00
# endif
2007-04-20 11:26:05 +00:00
# include "core/action.h"
2013-10-22 16:08:17 +00:00
# include "core/audioplayer.h"
2013-02-24 21:58:53 +00:00
# include "core/document_p.h"
2007-02-25 00:07:59 +00:00
# include "core/form.h"
2005-01-02 14:37:49 +00:00
# include "core/generator.h"
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# include "core/misc.h"
2008-08-25 01:59:23 +00:00
# include "core/movie.h"
2013-10-22 16:08:17 +00:00
# include "core/page.h"
# include "core/page_p.h"
2009-07-27 14:15:33 +00:00
# include "core/sourcereference.h"
2012-11-08 20:29:09 +00:00
# include "core/tile.h"
2014-02-24 22:42:10 +00:00
# include "magnifierview.h"
2006-03-28 22:22:10 +00:00
# include "settings.h"
2012-10-15 22:27:42 +00:00
# include "settings_core.h"
2013-03-26 21:43:03 +00:00
# include "url_utils.h"
2014-02-24 22:42:10 +00:00
# include "videowidget.h"
2004-09-26 23:39:39 +00:00
2014-09-27 13:41:47 +00:00
static const int pageflags = PagePainter : : Accessibility | PagePainter : : EnhanceLinks | PagePainter : : EnhanceImages | PagePainter : : Highlights | PagePainter : : TextSelection | PagePainter : : Annotations ;
2006-07-09 11:10:24 +00:00
2020-05-15 17:44:04 +00:00
static const std : : array < float , 16 > kZoomValues { 0.12 , 0.25 , 0.33 , 0.50 , 0.66 , 0.75 , 1.00 , 1.25 , 1.50 , 2.00 , 4.00 , 8.00 , 16.00 , 25.00 , 50.00 , 100.00 } ;
2014-05-05 22:43:40 +00:00
2019-08-25 10:19:43 +00:00
// This is the length of the text that will be shown when the user is searching for a specific piece of text.
static const int searchTextPreviewLength = 21 ;
// When following a link, only a preview of this length will be used to set the text of the action.
static const int linkTextPreviewLength = 30 ;
2009-05-17 10:17:35 +00:00
static inline double normClamp ( double value , double def )
{
return ( value < 0.0 | | value > 1.0 ) ? def : value ;
}
2011-10-12 13:50:56 +00:00
struct TableSelectionPart {
PageViewItem * item ;
Okular : : NormalizedRect rectInItem ;
Okular : : NormalizedRect rectInSelection ;
2011-10-12 13:59:05 +00:00
TableSelectionPart ( PageViewItem * item_p , const Okular : : NormalizedRect & rectInItem_p , const Okular : : NormalizedRect & rectInSelection_p ) ;
2011-10-12 13:50:56 +00:00
} ;
2011-10-12 13:59:05 +00:00
TableSelectionPart : : TableSelectionPart ( PageViewItem * item_p , const Okular : : NormalizedRect & rectInItem_p , const Okular : : NormalizedRect & rectInSelection_p )
2011-10-12 13:50:56 +00:00
: item ( item_p )
, rectInItem ( rectInItem_p )
, rectInSelection ( rectInSelection_p )
{
}
2004-09-26 23:39:39 +00:00
// structure used internally by PageView for data storage
class PageViewPrivate
{
public :
2007-10-18 22:09:49 +00:00
PageViewPrivate ( PageView * qq ) ;
FormWidgetsController * formWidgetsController ( ) ;
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-03-05 02:13:09 +00:00
OkularTTS * tts ( ) ;
2014-11-08 04:33:23 +00:00
# endif
2008-02-26 20:54:31 +00:00
QString selectedText ( ) const ;
2007-10-18 22:09:49 +00:00
2005-01-09 23:37:07 +00:00
// the document, pageviewItems and the 'visible cache'
2007-10-18 22:09:49 +00:00
PageView * q ;
2006-09-21 08:45:36 +00:00
Okular : : Document * document ;
2006-03-24 20:40:02 +00:00
QVector < PageViewItem * > items ;
QLinkedList < PageViewItem * > visibleItems ;
2014-02-24 22:42:10 +00:00
MagnifierView * magnifierView ;
2004-09-26 23:39:39 +00:00
2005-03-05 15:59:15 +00:00
// view layout (columns and continuous in Settings), zoom and mouse
2004-09-26 23:39:39 +00:00
PageView : : ZoomMode zoomMode ;
float zoomFactor ;
2019-11-15 16:08:25 +00:00
QPoint mouseGrabOffset ;
2005-01-29 12:32:59 +00:00
QPoint mousePressPos ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
QPoint mouseSelectPos ;
2018-12-05 23:24:39 +00:00
QPoint previousMouseMovePos ;
2005-03-24 19:10:41 +00:00
int mouseMidLastY ;
2005-06-24 16:41:55 +00:00
bool mouseSelecting ;
2004-10-30 20:54:48 +00:00
QRect mouseSelectionRect ;
2005-06-24 16:41:55 +00:00
QColor mouseSelectionColor ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
bool mouseTextSelecting ;
2006-09-26 22:22:01 +00:00
QSet < int > pagesWithTextSelection ;
2005-06-24 16:41:55 +00:00
bool mouseOnRect ;
2014-12-10 14:33:27 +00:00
int mouseMode ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
MouseAnnotation * mouseAnnotation ;
2006-10-07 14:40:32 +00:00
2011-10-12 13:50:56 +00:00
// table selection
QList < double > tableSelectionCols ;
QList < double > tableSelectionRows ;
QList < TableSelectionPart > tableSelectionParts ;
2011-10-31 15:33:03 +00:00
bool tableDividersGuessed ;
2011-10-12 13:50:56 +00:00
2011-10-17 19:56:45 +00:00
int lastSourceLocationViewportPageNumber ;
double lastSourceLocationViewportNormalizedX ;
double lastSourceLocationViewportNormalizedY ;
2017-03-03 22:55:06 +00:00
int controlWheelAccumulatedDelta ;
2020-09-11 14:46:53 +00:00
// for everything except PgUp/PgDn and scroll to arbitrary locations
2020-09-11 21:19:36 +00:00
const int baseShortScrollDuration = 100 ;
int currentShortScrollDuration ;
2020-09-11 14:46:53 +00:00
// for PgUp/PgDn and scroll to arbitrary locations
2020-09-11 21:19:36 +00:00
const int baseLongScrollDuration = baseShortScrollDuration * 2 ;
int currentLongScrollDuration ;
2020-09-11 14:46:53 +00:00
2005-02-01 18:24:16 +00:00
// auto scroll
2004-10-06 00:05:49 +00:00
int scrollIncrement ;
2005-02-01 18:24:16 +00:00
QTimer * autoScrollTimer ;
2005-02-18 18:24:45 +00:00
// annotations
2005-03-04 23:06:24 +00:00
PageViewAnnotator * annotator ;
2006-08-08 15:31:13 +00:00
// text annotation dialogs list
2017-10-25 12:59:17 +00:00
QSet < AnnotWindow * > m_annowindows ;
2005-02-01 18:24:16 +00:00
// other stuff
2011-03-17 15:24:44 +00:00
QTimer * delayResizeEventTimer ;
2004-09-30 18:04:09 +00:00
bool dirtyLayout ;
2005-02-01 18:24:16 +00:00
bool blockViewport ; // prevents changes to viewport
2005-01-21 20:05:36 +00:00
bool blockPixmapsRequest ; // prevent pixmap requests
PageViewMessage * messageWindow ; // in pageviewutils.h
2007-02-25 00:07:59 +00:00
bool m_formsVisible ;
2007-10-18 22:09:49 +00:00
FormWidgetsController * formsWidgetController ;
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-03-05 02:13:09 +00:00
OkularTTS * m_tts ;
2014-11-08 04:33:23 +00:00
# endif
2008-03-07 16:09:08 +00:00
QTimer * refreshTimer ;
2017-03-02 21:42:50 +00:00
QSet < int > refreshPages ;
2004-09-26 23:39:39 +00:00
2015-08-27 20:09:02 +00:00
// bbox state for Trim to Selection mode
Okular : : NormalizedRect trimBoundingBox ;
2004-09-26 23:39:39 +00:00
2008-12-08 16:09:15 +00:00
// infinite resizing loop prevention
2010-07-20 22:24:57 +00:00
bool verticalScrollBarVisible ;
2013-08-18 15:19:20 +00:00
bool horizontalScrollBarVisible ;
2008-12-08 16:09:15 +00:00
2006-11-22 21:32:21 +00:00
// drag scroll
QPoint dragScrollVector ;
QTimer dragScrollTimer ;
2010-03-25 20:59:16 +00:00
// left click depress
QTimer leftClickTimer ;
2004-09-26 23:39:39 +00:00
// actions
2014-08-13 10:45:40 +00:00
QAction * aRotateClockwise ;
QAction * aRotateCounterClockwise ;
QAction * aRotateOriginal ;
2015-08-27 20:09:02 +00:00
KActionMenu * aTrimMode ;
2008-05-27 14:00:59 +00:00
KToggleAction * aTrimMargins ;
2020-07-14 10:03:47 +00:00
KToggleAction * aReadingDirection ;
2014-08-13 10:45:40 +00:00
QAction * aMouseNormal ;
QAction * aMouseSelect ;
QAction * aMouseTextSelect ;
QAction * aMouseTableSelect ;
QAction * aMouseMagnifier ;
2015-08-27 20:09:02 +00:00
KToggleAction * aTrimToSelection ;
2004-10-29 21:52:06 +00:00
KSelectAction * aZoom ;
2014-08-10 12:08:47 +00:00
QAction * aZoomIn ;
QAction * aZoomOut ;
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
QAction * aZoomActual ;
2004-10-29 21:52:06 +00:00
KToggleAction * aZoomFitWidth ;
KToggleAction * aZoomFitPage ;
2013-08-18 15:19:20 +00:00
KToggleAction * aZoomAutoFit ;
2020-03-12 21:03:47 +00:00
KActionMenu * aViewModeMenu ;
QActionGroup * viewModeActionGroup ;
2005-03-05 15:59:15 +00:00
KToggleAction * aViewContinuous ;
2007-01-09 11:02:04 +00:00
QAction * aPrevAction ;
2020-06-26 20:20:20 +00:00
KToggleAction * aToggleForms ;
2014-08-13 10:45:40 +00:00
QAction * aSpeakDoc ;
QAction * aSpeakPage ;
QAction * aSpeakStop ;
2019-09-19 19:50:58 +00:00
QAction * aSpeakPauseResume ;
2006-06-25 16:34:11 +00:00
KActionCollection * actionCollection ;
2011-10-12 19:36:01 +00:00
QActionGroup * mouseModeActionGroup ;
Replace ToolAction by ToggleActionMenu
Summary:
This replaces ToolAction by a near-drop-in replacement named ToggleActionMenu. The new annotation toolbar already uses this (D15580).
Unlike ToolAction, ToggleActionMenu inherits from KActionMenu to be more flexible.
* Menu can be set from outside, not hard coded.
* Default action for toolbar button is controllable from outside. (Theoretically, the button could trigger //anything// now.)
* KActionMenu instead of KSelectAction:
- Pluggable in other menus, thus called “Menu”.
- Doesn’t make the actions exclusive, so //any// actions can be added to the menu.
* ImplicitDefaultAction mode can choose the default action of the toolbar buttons automatically, by looking for the first checked action in the menu.
Toolbar buttons use the default action //of// this menu, not this menu itself as action.
Because the default action is configurable now, D21622 and D21635 (where we tried to fine-tune ToolAction) become obsolete.
Screenshot:
Everything like before, here with mouse_selecttool added to Tools menu to show submenu capability.
{F6884228}
Test Plan:
ToolAction replacement and ImplicitDefaultAction mode:
* Open Okular and look at toolbar button -> has correct tool selected.
* Open a document.
* Look at toolbar button menu -> Correct menu entries (like before, with ToolAction).
* Select some selection tools through shortcuts and toolbar button -> behaves correctly.
Usage as submenu:
* Add ToggleActionMenu ("mouse_selecttool") to menubar (..../kxmlgui5/okular/part.rc) -> Submenu looks correctly, has no checkbox attached and so on...
Toolbar buttons:
* Add diverse other actions to the menu -> still works as before.
* Add actions when toolbar buttons are already created -> actions are added to existing buttons.
* setDefaultAction() to some completely unrelated action. -> ToggleActionMenu does not get confused.
Reviewers: simgunz
Reviewed By: simgunz
Subscribers: aacid, ngraham, simgunz, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D21971
2020-02-01 18:54:18 +00:00
ToggleActionMenu * aMouseModeMenu ;
2015-03-17 07:47:52 +00:00
QAction * aFitWindowToPage ;
2006-10-28 22:58:05 +00:00
2007-05-19 10:19:25 +00:00
int setting_viewCols ;
2016-07-25 23:37:54 +00:00
bool rtl_Mode ;
2012-10-15 18:11:47 +00:00
// Keep track of whether tablet pen is currently pressed down
bool penDown ;
2017-09-21 20:16:31 +00:00
// Keep track of mouse over link object
const Okular : : ObjectRect * mouseOverLinkObject ;
2019-11-15 16:08:25 +00:00
QScroller * scroller ;
2004-09-26 23:39:39 +00:00
} ;
2007-10-18 22:09:49 +00:00
PageViewPrivate : : PageViewPrivate ( PageView * qq )
: q ( qq )
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2017-09-05 21:27:18 +00:00
, m_tts ( nullptr )
2014-11-08 04:33:23 +00:00
# endif
2007-10-18 22:09:49 +00:00
{
}
FormWidgetsController * PageViewPrivate : : formWidgetsController ( )
{
if ( ! formsWidgetController ) {
2013-06-03 20:46:41 +00:00
formsWidgetController = new FormWidgetsController ( document ) ;
2020-02-19 16:45:37 +00:00
QObject : : connect ( formsWidgetController , & FormWidgetsController : : changed , q , & PageView : : slotFormChanged ) ;
QObject : : connect ( formsWidgetController , & FormWidgetsController : : action , q , & PageView : : slotAction ) ;
2019-06-26 00:58:28 +00:00
QObject : : connect ( formsWidgetController , & FormWidgetsController : : formatAction , q , [ this ] ( const Okular : : Action * action , Okular : : FormFieldText * fft ) { document - > processFormatAction ( action , fft ) ; } ) ;
2019-07-27 17:53:31 +00:00
QObject : : connect ( formsWidgetController , & FormWidgetsController : : keystrokeAction , q , [ this ] ( const Okular : : Action * action , Okular : : FormFieldText * fft , bool & ok ) { document - > processKeystrokeAction ( action , fft , ok ) ; } ) ;
2019-07-30 20:25:35 +00:00
QObject : : connect ( formsWidgetController , & FormWidgetsController : : focusAction , q , [ this ] ( const Okular : : Action * action , Okular : : FormFieldText * fft ) { document - > processFocusAction ( action , fft ) ; } ) ;
2019-08-16 23:15:47 +00:00
QObject : : connect ( formsWidgetController , & FormWidgetsController : : validateAction , q , [ this ] ( const Okular : : Action * action , Okular : : FormFieldText * fft , bool & ok ) { document - > processValidateAction ( action , fft , ok ) ; } ) ;
2007-10-18 22:09:49 +00:00
}
return formsWidgetController ;
}
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-03-05 02:13:09 +00:00
OkularTTS * PageViewPrivate : : tts ( )
{
if ( ! m_tts ) {
2008-08-23 11:09:04 +00:00
m_tts = new OkularTTS ( q ) ;
2008-03-05 12:05:48 +00:00
if ( aSpeakStop ) {
2019-09-26 05:46:33 +00:00
QObject : : connect ( m_tts , & OkularTTS : : canPauseOrResume , aSpeakStop , & QAction : : setEnabled ) ;
2008-03-05 12:05:48 +00:00
}
2019-09-26 05:46:33 +00:00
if ( aSpeakPauseResume ) {
QObject : : connect ( m_tts , & OkularTTS : : canPauseOrResume , aSpeakPauseResume , & QAction : : setEnabled ) ;
}
2008-03-05 02:13:09 +00:00
}
return m_tts ;
}
2014-11-08 04:33:23 +00:00
# endif
2008-03-05 02:13:09 +00:00
2004-09-30 18:16:12 +00:00
/* PageView. What's in this file? -> quick overview.
* Code weight ( in rows ) and meaning :
* 160 - constructor and creating actions plus their connected slots ( empty stuff )
* 70 - DocumentObserver inherited methodes ( important )
2014-04-09 21:29:13 +00:00
* 550 - events : mouse , keyboard , drag
2005-03-05 15:59:15 +00:00
* 170 - slotRelayoutPages : set contents of the scrollview on continuous / single modes
2004-09-30 18:16:12 +00:00
* 100 - zoom : zooming pages in different ways , keeping update the toolbar actions , etc . .
2004-10-30 20:54:48 +00:00
* other misc functions : only slotRequestVisiblePixmaps and pickItemOnPoint noticeable ,
2004-09-30 18:16:12 +00:00
* and many insignificant stuff like this comment : - )
2004-09-26 23:39:39 +00:00
*/
2006-09-21 08:45:36 +00:00
PageView : : PageView ( QWidget * parent , Okular : : Document * document )
2009-06-29 20:55:50 +00:00
: QAbstractScrollArea ( parent )
2019-04-25 21:10:48 +00:00
, Okular : : View ( QStringLiteral ( " PageView " ) )
2004-09-26 23:39:39 +00:00
{
// create and initialize private storage structure
2007-10-18 22:09:49 +00:00
d = new PageViewPrivate ( this ) ;
2004-09-26 23:39:39 +00:00
d - > document = document ;
2017-09-05 21:27:18 +00:00
d - > aRotateClockwise = nullptr ;
d - > aRotateCounterClockwise = nullptr ;
d - > aRotateOriginal = nullptr ;
2020-03-12 21:03:47 +00:00
d - > aViewModeMenu = nullptr ;
2008-09-10 11:26:53 +00:00
d - > zoomMode = PageView : : ZoomFitWidth ;
2008-05-31 20:45:30 +00:00
d - > zoomFactor = 1.0 ;
2005-06-24 16:41:55 +00:00
d - > mouseSelecting = false ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
d - > mouseTextSelecting = false ;
2004-12-10 16:04:45 +00:00
d - > mouseOnRect = false ;
2014-12-10 14:33:27 +00:00
d - > mouseMode = Okular : : Settings : : mouseMode ( ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
d - > mouseAnnotation = new MouseAnnotation ( this , document ) ;
2011-10-31 15:33:03 +00:00
d - > tableDividersGuessed = false ;
2011-11-05 09:18:08 +00:00
d - > lastSourceLocationViewportPageNumber = - 1 ;
d - > lastSourceLocationViewportNormalizedX = 0.0 ;
d - > lastSourceLocationViewportNormalizedY = 0.0 ;
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta = 0 ;
2020-09-11 21:19:36 +00:00
d - > currentShortScrollDuration = d - > baseShortScrollDuration ;
d - > currentLongScrollDuration = d - > baseLongScrollDuration ;
2004-10-06 00:05:49 +00:00
d - > scrollIncrement = 0 ;
2017-09-05 21:27:18 +00:00
d - > autoScrollTimer = nullptr ;
d - > annotator = nullptr ;
2004-09-30 18:04:09 +00:00
d - > dirtyLayout = false ;
2005-01-09 23:37:07 +00:00
d - > blockViewport = false ;
2005-01-21 20:05:36 +00:00
d - > blockPixmapsRequest = false ;
2004-10-20 16:41:13 +00:00
d - > messageWindow = new PageViewMessage ( this ) ;
2007-02-25 00:07:59 +00:00
d - > m_formsVisible = false ;
2017-09-05 21:27:18 +00:00
d - > formsWidgetController = nullptr ;
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2017-09-05 21:27:18 +00:00
d - > m_tts = nullptr ;
2014-11-08 04:33:23 +00:00
# endif
2017-09-05 21:27:18 +00:00
d - > refreshTimer = nullptr ;
d - > aRotateClockwise = nullptr ;
d - > aRotateCounterClockwise = nullptr ;
d - > aRotateOriginal = nullptr ;
d - > aTrimMode = nullptr ;
d - > aTrimMargins = nullptr ;
d - > aTrimToSelection = nullptr ;
2020-07-14 10:03:47 +00:00
d - > aReadingDirection = nullptr ;
2017-09-05 21:27:18 +00:00
d - > aMouseNormal = nullptr ;
d - > aMouseSelect = nullptr ;
d - > aMouseTextSelect = nullptr ;
d - > aZoomFitWidth = nullptr ;
d - > aZoomFitPage = nullptr ;
d - > aZoomAutoFit = nullptr ;
2020-03-12 21:03:47 +00:00
d - > aViewModeMenu = nullptr ;
2017-09-05 21:27:18 +00:00
d - > aViewContinuous = nullptr ;
2020-03-12 21:03:47 +00:00
d - > viewModeActionGroup = nullptr ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
d - > aToggleForms = nullptr ;
d - > aSpeakDoc = nullptr ;
d - > aSpeakPage = nullptr ;
d - > aSpeakStop = nullptr ;
2019-09-19 19:50:58 +00:00
d - > aSpeakPauseResume = nullptr ;
2017-09-05 21:27:18 +00:00
d - > actionCollection = nullptr ;
2007-05-19 10:19:25 +00:00
d - > setting_viewCols = Okular : : Settings : : viewColumns ( ) ;
2016-07-25 23:37:54 +00:00
d - > rtl_Mode = Okular : : Settings : : rtlReadingDirection ( ) ;
2017-09-05 21:27:18 +00:00
d - > mouseModeActionGroup = nullptr ;
2020-02-09 23:42:00 +00:00
d - > aMouseModeMenu = nullptr ;
2012-10-15 18:11:47 +00:00
d - > penDown = false ;
2017-09-05 21:27:18 +00:00
d - > aMouseMagnifier = nullptr ;
d - > aFitWindowToPage = nullptr ;
2015-08-27 20:09:02 +00:00
d - > trimBoundingBox = Okular : : NormalizedRect ( ) ; // Null box
2010-09-11 13:34:22 +00:00
2011-09-28 21:55:54 +00:00
switch ( Okular : : Settings : : zoomMode ( ) ) {
2011-09-28 21:54:03 +00:00
case 0 : {
d - > zoomFactor = 1 ;
d - > zoomMode = PageView : : ZoomFixed ;
break ;
}
case 1 : {
d - > zoomMode = PageView : : ZoomFitWidth ;
break ;
}
case 2 : {
d - > zoomMode = PageView : : ZoomFitPage ;
break ;
}
2013-08-18 15:19:20 +00:00
case 3 : {
d - > zoomMode = PageView : : ZoomFitAuto ;
break ;
}
2011-09-28 21:54:03 +00:00
}
2011-03-17 15:24:44 +00:00
d - > delayResizeEventTimer = new QTimer ( this ) ;
d - > delayResizeEventTimer - > setSingleShot ( true ) ;
2020-02-21 16:45:03 +00:00
d - > delayResizeEventTimer - > setObjectName ( QStringLiteral ( " delayResizeEventTimer " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > delayResizeEventTimer , & QTimer : : timeout , this , & PageView : : delayedResizeEvent ) ;
2004-09-27 21:36:25 +00:00
2007-05-28 15:29:29 +00:00
setFrameStyle ( QFrame : : NoFrame ) ;
2006-06-03 13:01:15 +00:00
setAttribute ( Qt : : WA_StaticContents ) ;
2015-10-29 12:37:11 +00:00
setObjectName ( QStringLiteral ( " okular::pageView " ) ) ;
2006-06-03 13:01:15 +00:00
2014-04-09 21:29:13 +00:00
// viewport setup: setup focus, and track mouse
2004-09-27 21:36:25 +00:00
viewport ( ) - > setFocusProxy ( this ) ;
2006-03-24 20:40:02 +00:00
viewport ( ) - > setFocusPolicy ( Qt : : StrongFocus ) ;
2009-06-29 20:55:50 +00:00
viewport ( ) - > setAttribute ( Qt : : WA_OpaquePaintEvent ) ;
viewport ( ) - > setAttribute ( Qt : : WA_NoSystemBackground ) ;
viewport ( ) - > setMouseTracking ( true ) ;
2009-07-07 16:53:33 +00:00
viewport ( ) - > setAutoFillBackground ( false ) ;
2019-11-15 16:08:25 +00:00
d - > scroller = QScroller : : scroller ( viewport ( ) ) ;
QScrollerProperties prop ;
prop . setScrollMetric ( QScrollerProperties : : DecelerationFactor , 0.3 ) ;
prop . setScrollMetric ( QScrollerProperties : : MaximumVelocity , 1 ) ;
2020-11-20 17:54:07 +00:00
prop . setScrollMetric ( QScrollerProperties : : AcceleratingFlickMaximumTime , 0.2 ) ; // Workaround for QTBUG-88249 (non-flick gestures recognized as accelerating flick)
2020-05-19 22:09:52 +00:00
prop . setScrollMetric ( QScrollerProperties : : HorizontalOvershootPolicy , QScrollerProperties : : OvershootAlwaysOff ) ;
prop . setScrollMetric ( QScrollerProperties : : VerticalOvershootPolicy , QScrollerProperties : : OvershootAlwaysOff ) ;
2020-09-15 12:11:30 +00:00
prop . setScrollMetric ( QScrollerProperties : : DragStartDistance , 0.0 ) ;
2019-11-15 16:08:25 +00:00
d - > scroller - > setScrollerProperties ( prop ) ;
2020-01-11 07:58:39 +00:00
connect ( d - > scroller , & QScroller : : stateChanged , this , & PageView : : slotRequestVisiblePixmaps ) ;
2009-06-29 20:55:50 +00:00
// the apparently "magic" value of 20 is the same used internally in QScrollArea
2017-05-21 21:36:20 +00:00
verticalScrollBar ( ) - > setCursor ( Qt : : ArrowCursor ) ;
2009-06-29 20:55:50 +00:00
verticalScrollBar ( ) - > setSingleStep ( 20 ) ;
2017-05-21 21:36:20 +00:00
horizontalScrollBar ( ) - > setCursor ( Qt : : ArrowCursor ) ;
2009-06-29 20:55:50 +00:00
horizontalScrollBar ( ) - > setSingleStep ( 20 ) ;
2004-09-27 21:36:25 +00:00
2020-09-11 15:52:14 +00:00
// make the smooth scroll animation durations respect the global animation
// scale
2020-09-11 21:19:36 +00:00
KConfigWatcher : : Ptr animationSpeedWatcher = KConfigWatcher : : create ( KSharedConfig : : openConfig ( ) ) ;
connect ( animationSpeedWatcher . data ( ) , & KConfigWatcher : : configChanged , this , [ this ] ( const KConfigGroup & group , const QByteArrayList & names ) {
if ( group . name ( ) = = QLatin1String ( " KDE " ) & & names . contains ( QByteArrayLiteral ( " AnimationDurationFactor " ) ) ) {
PageView : : updateSmoothScrollAnimationSpeed ( ) ;
}
} ) ;
2020-09-11 15:52:14 +00:00
2019-01-11 07:09:34 +00:00
// connect the padding of the viewport to pixmaps requests
2015-10-29 12:37:11 +00:00
connect ( horizontalScrollBar ( ) , & QAbstractSlider : : valueChanged , this , & PageView : : slotRequestVisiblePixmaps ) ;
connect ( verticalScrollBar ( ) , & QAbstractSlider : : valueChanged , this , & PageView : : slotRequestVisiblePixmaps ) ;
2019-11-15 16:08:25 +00:00
2020-10-12 11:16:34 +00:00
// Keep the scroller in sync with user input on the scrollbars.
// QAbstractSlider::sliderMoved() and sliderReleased are the intuitive signals,
// but are only emitted when the “slider is down”, i. e. not when the user scrolls on the scrollbar.
// QAbstractSlider::actionTriggered() is emitted in all user input cases,
// but before the value() changes, so we need queued connection here.
2019-11-15 16:08:25 +00:00
auto update_scroller = [ = ] ( ) {
d - > scroller - > scrollTo ( QPoint ( horizontalScrollBar ( ) - > value ( ) , verticalScrollBar ( ) - > value ( ) ) , 0 ) ; // sync scroller with scrollbar
} ;
2020-10-12 11:16:34 +00:00
connect ( verticalScrollBar ( ) , & QAbstractSlider : : actionTriggered , this , update_scroller , Qt : : QueuedConnection ) ;
connect ( horizontalScrollBar ( ) , & QAbstractSlider : : actionTriggered , this , update_scroller , Qt : : QueuedConnection ) ;
2019-11-15 16:08:25 +00:00
2015-10-29 12:37:11 +00:00
connect ( & d - > dragScrollTimer , & QTimer : : timeout , this , & PageView : : slotDragScroll ) ;
2019-11-15 16:08:25 +00:00
2010-03-25 20:59:16 +00:00
d - > leftClickTimer . setSingleShot ( true ) ;
2015-10-29 12:37:11 +00:00
connect ( & d - > leftClickTimer , & QTimer : : timeout , this , & PageView : : slotShowSizeAllCursor ) ;
2010-03-25 20:59:16 +00:00
2004-09-26 23:39:39 +00:00
// set a corner button to resize the view to the page size
2004-10-29 21:52:06 +00:00
// QPushButton * resizeButton = new QPushButton( viewport() );
// resizeButton->setPixmap( SmallIcon("crop") );
// setCornerWidget( resizeButton );
// resizeButton->setEnabled( false );
2004-09-26 23:39:39 +00:00
// connect(...);
2006-08-30 14:17:22 +00:00
setAttribute ( Qt : : WA_InputMethodEnabled , true ) ;
2006-09-20 13:58:28 +00:00
2017-03-11 17:33:59 +00:00
// Grab pinch gestures to zoom and rotate the view
2016-10-15 13:22:35 +00:00
grabGesture ( Qt : : PinchGesture ) ;
2014-02-24 22:42:10 +00:00
d - > magnifierView = new MagnifierView ( document , this ) ;
d - > magnifierView - > hide ( ) ;
2014-02-24 23:04:57 +00:00
d - > magnifierView - > setGeometry ( 0 , 0 , 351 , 201 ) ; // TODO: more dynamic?
2014-02-24 22:42:10 +00:00
2015-10-29 12:37:11 +00:00
connect ( document , & Okular : : Document : : processMovieAction , this , & PageView : : slotProcessMovieAction ) ;
connect ( document , & Okular : : Document : : processRenditionAction , this , & PageView : : slotProcessRenditionAction ) ;
2012-09-27 12:15:58 +00:00
2006-09-20 13:58:28 +00:00
// schedule the welcome message
2006-10-19 21:18:39 +00:00
QMetaObject : : invokeMethod ( this , " slotShowWelcome " , Qt : : QueuedConnection ) ;
2004-09-26 23:39:39 +00:00
}
PageView : : ~ PageView ( )
{
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-03-05 15:40:36 +00:00
if ( d - > m_tts )
d - > m_tts - > stopAllSpeechs ( ) ;
2014-11-08 04:33:23 +00:00
# endif
2008-03-05 15:40:36 +00:00
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
delete d - > mouseAnnotation ;
2008-03-05 15:40:36 +00:00
2005-02-18 18:24:45 +00:00
// delete the local storage structure
2013-04-05 22:22:48 +00:00
2012-03-07 22:51:36 +00:00
// We need to assign it to a different list otherwise slotAnnotationWindowDestroyed
// will bite us and clear d->m_annowindows
2017-10-25 12:59:17 +00:00
QSet < AnnotWindow * > annowindows = d - > m_annowindows ;
2012-03-07 22:51:36 +00:00
d - > m_annowindows . clear ( ) ;
qDeleteAll ( annowindows ) ;
2006-11-19 13:20:22 +00:00
// delete all widgets
2019-03-26 22:37:30 +00:00
qDeleteAll ( d - > items ) ;
2007-10-18 22:09:49 +00:00
delete d - > formsWidgetController ;
2006-02-18 12:06:52 +00:00
d - > document - > removeObserver ( this ) ;
2004-09-26 23:39:39 +00:00
delete d ;
}
2007-07-14 12:31:26 +00:00
void PageView : : setupBaseActions ( KActionCollection * ac )
{
d - > actionCollection = ac ;
// Zoom actions ( higher scales takes lots of memory! )
2015-10-29 12:37:11 +00:00
d - > aZoom = new KSelectAction ( QIcon : : fromTheme ( QStringLiteral ( " page-zoom " ) ) , i18n ( " Zoom " ) , this ) ;
ac - > addAction ( QStringLiteral ( " zoom_to " ) , d - > aZoom ) ;
2007-07-14 12:31:26 +00:00
d - > aZoom - > setEditable ( true ) ;
2020-05-15 17:44:04 +00:00
d - > aZoom - > setMaxComboViewCount ( kZoomValues . size ( ) + 3 ) ;
2020-02-20 14:48:08 +00:00
connect ( d - > aZoom , QOverload < QAction * > : : of ( & KSelectAction : : triggered ) , this , & PageView : : slotZoom ) ;
2007-07-14 12:31:26 +00:00
updateZoomText ( ) ;
2011-07-31 19:22:04 +00:00
d - > aZoomIn = KStandardAction : : zoomIn ( this , SLOT ( slotZoomIn ( ) ) , ac ) ;
2007-07-14 12:31:26 +00:00
2011-07-31 19:22:04 +00:00
d - > aZoomOut = KStandardAction : : zoomOut ( this , SLOT ( slotZoomOut ( ) ) , ac ) ;
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
d - > aZoomActual = KStandardAction : : actualSize ( this , & PageView : : slotZoomActual , ac ) ;
d - > aZoomActual - > setText ( i18n ( " Zoom to 100% " ) ) ;
2007-07-14 12:31:26 +00:00
}
2011-10-12 19:36:01 +00:00
void PageView : : setupViewerActions ( KActionCollection * ac )
2004-09-26 23:39:39 +00:00
{
2006-06-25 16:34:11 +00:00
d - > actionCollection = ac ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aZoomIn , QKeySequence ( Qt : : CTRL | Qt : : ALT | Qt : : Key_Plus ) ) ;
ac - > setDefaultShortcut ( d - > aZoomOut , QKeySequence ( Qt : : CTRL | Qt : : ALT | Qt : : Key_Minus ) ) ;
2011-10-12 19:36:01 +00:00
2007-01-19 21:43:53 +00:00
// orientation menu actions
2015-10-29 12:37:11 +00:00
d - > aRotateClockwise = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " object-rotate-right " ) ) , i18n ( " Rotate &Right " ) , this ) ;
2007-11-02 00:07:32 +00:00
d - > aRotateClockwise - > setIconText ( i18nc ( " Rotate right " , " Right " ) ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_orientation_rotate_cw " ) , d - > aRotateClockwise ) ;
2007-08-28 12:04:18 +00:00
d - > aRotateClockwise - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aRotateClockwise , & QAction : : triggered , this , & PageView : : slotRotateClockwise ) ;
d - > aRotateCounterClockwise = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " object-rotate-left " ) ) , i18n ( " Rotate &Left " ) , this ) ;
2007-11-02 00:07:32 +00:00
d - > aRotateCounterClockwise - > setIconText ( i18nc ( " Rotate left " , " Left " ) ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_orientation_rotate_ccw " ) , d - > aRotateCounterClockwise ) ;
2007-08-28 12:04:18 +00:00
d - > aRotateCounterClockwise - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aRotateCounterClockwise , & QAction : : triggered , this , & PageView : : slotRotateCounterClockwise ) ;
2014-08-13 10:45:40 +00:00
d - > aRotateOriginal = new QAction ( i18n ( " Original Orientation " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_orientation_original " ) , d - > aRotateOriginal ) ;
2007-08-28 12:04:18 +00:00
d - > aRotateOriginal - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aRotateOriginal , & QAction : : triggered , this , & PageView : : slotRotateOriginal ) ;
2007-01-19 21:43:53 +00:00
2015-08-27 20:09:02 +00:00
// Trim View actions
d - > aTrimMode = new KActionMenu ( i18n ( " &Trim View " ) , this ) ;
d - > aTrimMode - > setDelayed ( false ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_trim_mode " ) , d - > aTrimMode ) ;
2020-07-10 22:15:05 +00:00
2019-01-26 20:56:54 +00:00
d - > aTrimMargins = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " trim-margins " ) ) , i18n ( " &Trim Margins " ) , d - > aTrimMode - > menu ( ) ) ;
2015-08-27 20:09:02 +00:00
d - > aTrimMode - > addAction ( d - > aTrimMargins ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_trim_margins " ) , d - > aTrimMargins ) ;
2019-09-18 11:41:19 +00:00
d - > aTrimMargins - > setData ( QVariant : : fromValue ( ( int ) Okular : : Settings : : EnumTrimMode : : Margins ) ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aTrimMargins , & QAction : : toggled , this , & PageView : : slotTrimMarginsToggled ) ;
2008-05-27 14:00:59 +00:00
d - > aTrimMargins - > setChecked ( Okular : : Settings : : trimMargins ( ) ) ;
2020-07-10 22:15:05 +00:00
2019-01-26 20:56:54 +00:00
d - > aTrimToSelection = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " trim-to-selection " ) ) , i18n ( " Trim To &Selection " ) , d - > aTrimMode - > menu ( ) ) ;
2015-08-27 20:09:02 +00:00
d - > aTrimMode - > addAction ( d - > aTrimToSelection ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_trim_selection " ) , d - > aTrimToSelection ) ;
2019-09-18 11:41:19 +00:00
d - > aTrimToSelection - > setData ( QVariant : : fromValue ( ( int ) Okular : : Settings : : EnumTrimMode : : Selection ) ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aTrimToSelection , & QAction : : toggled , this , & PageView : : slotTrimToSelectionToggled ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
d - > aZoomFitWidth = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " zoom-fit-width " ) ) , i18n ( " Fit &Width " ) , this ) ;
ac - > addAction ( QStringLiteral ( " view_fit_to_width " ) , d - > aZoomFitWidth ) ;
connect ( d - > aZoomFitWidth , & QAction : : toggled , this , & PageView : : slotFitToWidthToggled ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
d - > aZoomFitPage = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " zoom-fit-best " ) ) , i18n ( " Fit &Page " ) , this ) ;
ac - > addAction ( QStringLiteral ( " view_fit_to_page " ) , d - > aZoomFitPage ) ;
connect ( d - > aZoomFitPage , & QAction : : toggled , this , & PageView : : slotFitToPageToggled ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
d - > aZoomAutoFit = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " zoom-fit-best " ) ) , i18n ( " &Auto Fit " ) , this ) ;
ac - > addAction ( QStringLiteral ( " view_auto_fit " ) , d - > aZoomAutoFit ) ;
connect ( d - > aZoomAutoFit , & QAction : : toggled , this , & PageView : : slotAutoFitToggled ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
d - > aFitWindowToPage = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " zoom-fit-width " ) ) , i18n ( " Fit Wi&ndow to Page " ) , this ) ;
2015-03-16 23:20:11 +00:00
d - > aFitWindowToPage - > setEnabled ( Okular : : Settings : : viewMode ( ) = = ( int ) Okular : : Settings : : EnumViewMode : : Single ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aFitWindowToPage , QKeySequence ( Qt : : CTRL | Qt : : Key_J ) ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " fit_window_to_page " ) , d - > aFitWindowToPage ) ;
connect ( d - > aFitWindowToPage , & QAction : : triggered , this , & PageView : : slotFitWindowToPage ) ;
2013-08-18 15:19:20 +00:00
2020-03-12 21:03:47 +00:00
// View Mode action menu (Single Page, Facing Pages,...(choose), and Continuous (on/off))
d - > aViewModeMenu = new KActionMenu ( QIcon : : fromTheme ( QStringLiteral ( " view-split-left-right " ) ) , i18n ( " &View Mode " ) , this ) ;
d - > aViewModeMenu - > setDelayed ( false ) ;
ac - > addAction ( QStringLiteral ( " view_render_mode " ) , d - > aViewModeMenu ) ;
2020-07-10 22:15:05 +00:00
2020-03-12 21:03:47 +00:00
d - > viewModeActionGroup = new QActionGroup ( this ) ;
auto addViewMode = [ = ] ( QAction * a , const QString & name , Okular : : Settings : : EnumViewMode : : type id ) {
a - > setCheckable ( true ) ;
a - > setData ( int ( id ) ) ;
d - > aViewModeMenu - > addAction ( a ) ;
ac - > addAction ( name , a ) ;
d - > viewModeActionGroup - > addAction ( a ) ;
} ;
2020-03-08 16:52:19 +00:00
addViewMode ( new QAction ( QIcon : : fromTheme ( QStringLiteral ( " view-pages-single " ) ) , i18nc ( " @item:inmenu " , " &Single Page " ) , this ) , QStringLiteral ( " view_render_mode_single " ) , Okular : : Settings : : EnumViewMode : : Single ) ;
addViewMode ( new QAction ( QIcon : : fromTheme ( QStringLiteral ( " view-pages-facing " ) ) , i18nc ( " @item:inmenu " , " &Facing Pages " ) , this ) , QStringLiteral ( " view_render_mode_facing " ) , Okular : : Settings : : EnumViewMode : : Facing ) ;
addViewMode ( new QAction ( QIcon : : fromTheme ( QStringLiteral ( " view-pages-facing-first-centered " ) ) , i18nc ( " @item:inmenu " , " Facing Pages (&Center First Page) " ) , this ) ,
2020-04-25 10:06:27 +00:00
QStringLiteral ( " view_render_mode_facing_center_first " ) ,
2020-03-12 21:03:47 +00:00
Okular : : Settings : : EnumViewMode : : FacingFirstCentered ) ;
2020-03-08 16:52:19 +00:00
addViewMode ( new QAction ( QIcon : : fromTheme ( QStringLiteral ( " view-pages-overview " ) ) , i18nc ( " @item:inmenu " , " &Overview " ) , this ) , QStringLiteral ( " view_render_mode_overview " ) , Okular : : Settings : : EnumViewMode : : Summary ) ;
2020-03-12 21:03:47 +00:00
const QList < QAction * > viewModeActions = d - > viewModeActionGroup - > actions ( ) ;
for ( QAction * viewModeAction : viewModeActions ) {
if ( viewModeAction - > data ( ) . toInt ( ) = = Okular : : Settings : : viewMode ( ) ) {
2010-01-10 01:19:16 +00:00
viewModeAction - > setChecked ( true ) ;
2020-03-12 21:03:47 +00:00
break ;
2010-01-10 01:19:16 +00:00
}
}
2020-03-12 21:03:47 +00:00
connect ( d - > viewModeActionGroup , & QActionGroup : : triggered , this , & PageView : : slotViewMode ) ;
2004-09-26 23:39:39 +00:00
2020-03-12 21:03:47 +00:00
// Continuous view action, add to view mode action menu.
d - > aViewModeMenu - > addSeparator ( ) ;
2020-03-08 16:52:19 +00:00
d - > aViewContinuous = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " view-pages-continuous " ) ) , i18n ( " &Continuous " ) , this ) ;
2020-03-12 21:03:47 +00:00
d - > aViewModeMenu - > addAction ( d - > aViewContinuous ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_continuous " ) , d - > aViewContinuous ) ;
connect ( d - > aViewContinuous , & QAction : : toggled , this , & PageView : : slotContinuousToggled ) ;
2006-09-21 08:45:36 +00:00
d - > aViewContinuous - > setChecked ( Okular : : Settings : : viewContinuous ( ) ) ;
2004-09-26 23:39:39 +00:00
2020-07-14 10:03:47 +00:00
// Reading direction toggle action. (Checked means RTL, unchecked means LTR.)
d - > aReadingDirection = new KToggleAction ( QIcon : : fromTheme ( QStringLiteral ( " format-text-direction-rtl " ) ) , i18nc ( " @action page layout " , " Use Right to Left Reading Direction " ) , this ) ;
d - > aReadingDirection - > setChecked ( Okular : : Settings : : rtlReadingDirection ( ) ) ;
ac - > addAction ( QStringLiteral ( " rtl_page_layout " ) , d - > aReadingDirection ) ;
connect ( d - > aReadingDirection , & QAction : : toggled , this , & PageView : : slotReadingDirectionToggled ) ;
connect ( Okular : : SettingsCore : : self ( ) , & Okular : : SettingsCore : : configChanged , this , & PageView : : slotUpdateReadingDirectionAction ) ;
2011-10-12 19:36:01 +00:00
// Mouse mode actions for viewer mode
d - > mouseModeActionGroup = new QActionGroup ( this ) ;
d - > mouseModeActionGroup - > setExclusive ( true ) ;
2019-06-06 17:39:30 +00:00
d - > aMouseNormal = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " transform-browse " ) ) , i18n ( " &Browse " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " mouse_drag " ) , d - > aMouseNormal ) ;
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
connect ( d - > aMouseNormal , & QAction : : toggled , this , & PageView : : slotMouseNormalToggled ) ;
2006-04-01 15:12:32 +00:00
d - > aMouseNormal - > setCheckable ( true ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aMouseNormal , QKeySequence ( Qt : : CTRL | Qt : : Key_1 ) ) ;
2011-10-12 19:36:01 +00:00
d - > aMouseNormal - > setActionGroup ( d - > mouseModeActionGroup ) ;
2012-03-09 17:43:40 +00:00
d - > aMouseNormal - > setChecked ( Okular : : Settings : : mouseMode ( ) = = Okular : : Settings : : EnumMouseMode : : Browse ) ;
2004-09-26 23:39:39 +00:00
Regularize tool names
Summary:
Currently, some of the items in the {nav Tools} menu have "tool" in the name, and some
do not. This is in any event redundant since they're in a menu with that word in it
already. In the toolbar, these actions become more inconsistent since their names change
and can even differ between what's shown in the pop-up menu and what's shown on the
button text.
This patch regularizes the names, stops changing the names for the toolbar versions, and
updates the docbook accordingly.
Test Plan:
{F6874459, size=full}
{F6874458, size=full}
Reviewers: #okular, #vdg, filipf
Reviewed By: #vdg, filipf
Subscribers: filipf, okular-devel, kde-doc-english
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D21621
2019-06-06 14:46:43 +00:00
QAction * mz = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " page-zoom " ) ) , i18n ( " &Zoom " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " mouse_zoom " ) , mz ) ;
connect ( mz , & QAction : : triggered , this , & PageView : : slotSetMouseZoom ) ;
2006-04-01 15:12:32 +00:00
mz - > setCheckable ( true ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( mz , QKeySequence ( Qt : : CTRL | Qt : : Key_2 ) ) ;
2011-10-12 19:36:01 +00:00
mz - > setActionGroup ( d - > mouseModeActionGroup ) ;
2012-03-09 17:43:40 +00:00
mz - > setChecked ( Okular : : Settings : : mouseMode ( ) = = Okular : : Settings : : EnumMouseMode : : Zoom ) ;
2013-10-26 09:40:41 +00:00
2014-08-13 10:45:40 +00:00
QAction * aToggleChangeColors = new QAction ( i18n ( " &Toggle Change Colors " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " toggle_change_colors " ) , aToggleChangeColors ) ;
connect ( aToggleChangeColors , & QAction : : triggered , this , & PageView : : slotToggleChangeColors ) ;
2011-10-12 19:36:01 +00:00
}
// WARNING: 'setupViewerActions' must have been called before this method
void PageView : : setupActions ( KActionCollection * ac )
{
d - > actionCollection = ac ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcuts ( d - > aZoomIn , KStandardShortcut : : zoomIn ( ) ) ;
ac - > setDefaultShortcuts ( d - > aZoomOut , KStandardShortcut : : zoomOut ( ) ) ;
2011-10-12 19:36:01 +00:00
// Mouse-Mode actions
Regularize tool names
Summary:
Currently, some of the items in the {nav Tools} menu have "tool" in the name, and some
do not. This is in any event redundant since they're in a menu with that word in it
already. In the toolbar, these actions become more inconsistent since their names change
and can even differ between what's shown in the pop-up menu and what's shown on the
button text.
This patch regularizes the names, stops changing the names for the toolbar versions, and
updates the docbook accordingly.
Test Plan:
{F6874459, size=full}
{F6874458, size=full}
Reviewers: #okular, #vdg, filipf
Reviewed By: #vdg, filipf
Subscribers: filipf, okular-devel, kde-doc-english
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D21621
2019-06-06 14:46:43 +00:00
d - > aMouseSelect = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " select-rectangular " ) ) , i18n ( " Area &Selection " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " mouse_select " ) , d - > aMouseSelect ) ;
connect ( d - > aMouseSelect , & QAction : : triggered , this , & PageView : : slotSetMouseSelect ) ;
2006-04-01 15:12:32 +00:00
d - > aMouseSelect - > setCheckable ( true ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aMouseSelect , Qt : : CTRL | Qt : : Key_3 ) ;
2014-10-04 19:48:01 +00:00
2011-10-12 19:36:01 +00:00
d - > aMouseSelect - > setActionGroup ( d - > mouseModeActionGroup ) ;
2012-03-09 17:43:40 +00:00
d - > aMouseSelect - > setChecked ( Okular : : Settings : : mouseMode ( ) = = Okular : : Settings : : EnumMouseMode : : RectSelect ) ;
2004-11-03 17:35:48 +00:00
2019-06-06 18:41:20 +00:00
d - > aMouseTextSelect = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-select-text " ) ) , i18n ( " &Text Selection " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " mouse_textselect " ) , d - > aMouseTextSelect ) ;
connect ( d - > aMouseTextSelect , & QAction : : triggered , this , & PageView : : slotSetMouseTextSelect ) ;
2006-09-26 22:22:01 +00:00
d - > aMouseTextSelect - > setCheckable ( true ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aMouseTextSelect , Qt : : CTRL | Qt : : Key_4 ) ;
2011-10-12 19:36:01 +00:00
d - > aMouseTextSelect - > setActionGroup ( d - > mouseModeActionGroup ) ;
2012-03-09 17:43:40 +00:00
d - > aMouseTextSelect - > setChecked ( Okular : : Settings : : mouseMode ( ) = = Okular : : Settings : : EnumMouseMode : : TextSelect ) ;
2006-09-26 22:22:01 +00:00
Regularize tool names
Summary:
Currently, some of the items in the {nav Tools} menu have "tool" in the name, and some
do not. This is in any event redundant since they're in a menu with that word in it
already. In the toolbar, these actions become more inconsistent since their names change
and can even differ between what's shown in the pop-up menu and what's shown on the
button text.
This patch regularizes the names, stops changing the names for the toolbar versions, and
updates the docbook accordingly.
Test Plan:
{F6874459, size=full}
{F6874458, size=full}
Reviewers: #okular, #vdg, filipf
Reviewed By: #vdg, filipf
Subscribers: filipf, okular-devel, kde-doc-english
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D21621
2019-06-06 14:46:43 +00:00
d - > aMouseTableSelect = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " table " ) ) , i18n ( " T&able Selection " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " mouse_tableselect " ) , d - > aMouseTableSelect ) ;
connect ( d - > aMouseTableSelect , & QAction : : triggered , this , & PageView : : slotSetMouseTableSelect ) ;
2011-10-12 13:50:56 +00:00
d - > aMouseTableSelect - > setCheckable ( true ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aMouseTableSelect , Qt : : CTRL | Qt : : Key_5 ) ;
2011-10-12 19:36:01 +00:00
d - > aMouseTableSelect - > setActionGroup ( d - > mouseModeActionGroup ) ;
2012-03-09 17:43:40 +00:00
d - > aMouseTableSelect - > setChecked ( Okular : : Settings : : mouseMode ( ) = = Okular : : Settings : : EnumMouseMode : : TableSelect ) ;
2011-10-12 13:50:56 +00:00
2015-10-29 12:37:11 +00:00
d - > aMouseMagnifier = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " document-preview " ) ) , i18n ( " &Magnifier " ) , this ) ;
ac - > addAction ( QStringLiteral ( " mouse_magnifier " ) , d - > aMouseMagnifier ) ;
connect ( d - > aMouseMagnifier , & QAction : : triggered , this , & PageView : : slotSetMouseMagnifier ) ;
2014-02-24 22:42:10 +00:00
d - > aMouseMagnifier - > setCheckable ( true ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( d - > aMouseMagnifier , Qt : : CTRL | Qt : : Key_6 ) ;
2014-02-24 22:42:10 +00:00
d - > aMouseMagnifier - > setActionGroup ( d - > mouseModeActionGroup ) ;
d - > aMouseMagnifier - > setChecked ( Okular : : Settings : : mouseMode ( ) = = Okular : : Settings : : EnumMouseMode : : Magnifier ) ;
Replace ToolAction by ToggleActionMenu
Summary:
This replaces ToolAction by a near-drop-in replacement named ToggleActionMenu. The new annotation toolbar already uses this (D15580).
Unlike ToolAction, ToggleActionMenu inherits from KActionMenu to be more flexible.
* Menu can be set from outside, not hard coded.
* Default action for toolbar button is controllable from outside. (Theoretically, the button could trigger //anything// now.)
* KActionMenu instead of KSelectAction:
- Pluggable in other menus, thus called “Menu”.
- Doesn’t make the actions exclusive, so //any// actions can be added to the menu.
* ImplicitDefaultAction mode can choose the default action of the toolbar buttons automatically, by looking for the first checked action in the menu.
Toolbar buttons use the default action //of// this menu, not this menu itself as action.
Because the default action is configurable now, D21622 and D21635 (where we tried to fine-tune ToolAction) become obsolete.
Screenshot:
Everything like before, here with mouse_selecttool added to Tools menu to show submenu capability.
{F6884228}
Test Plan:
ToolAction replacement and ImplicitDefaultAction mode:
* Open Okular and look at toolbar button -> has correct tool selected.
* Open a document.
* Look at toolbar button menu -> Correct menu entries (like before, with ToolAction).
* Select some selection tools through shortcuts and toolbar button -> behaves correctly.
Usage as submenu:
* Add ToggleActionMenu ("mouse_selecttool") to menubar (..../kxmlgui5/okular/part.rc) -> Submenu looks correctly, has no checkbox attached and so on...
Toolbar buttons:
* Add diverse other actions to the menu -> still works as before.
* Add actions when toolbar buttons are already created -> actions are added to existing buttons.
* setDefaultAction() to some completely unrelated action. -> ToggleActionMenu does not get confused.
Reviewers: simgunz
Reviewed By: simgunz
Subscribers: aacid, ngraham, simgunz, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D21971
2020-02-01 18:54:18 +00:00
// Mouse-Mode action menu
d - > aMouseModeMenu = new ToggleActionMenu ( QIcon ( ) , QString ( ) , this , ToggleActionMenu : : MenuButtonPopup , ToggleActionMenu : : ImplicitDefaultAction ) ;
d - > aMouseModeMenu - > addAction ( d - > aMouseSelect ) ;
d - > aMouseModeMenu - > addAction ( d - > aMouseTextSelect ) ;
d - > aMouseModeMenu - > addAction ( d - > aMouseTableSelect ) ;
d - > aMouseModeMenu - > suggestDefaultAction ( d - > aMouseTextSelect ) ;
d - > aMouseModeMenu - > setText ( i18nc ( " @action " , " Selection Tools " ) ) ;
ac - > addAction ( QStringLiteral ( " mouse_selecttools " ) , d - > aMouseModeMenu ) ;
2008-03-05 11:06:55 +00:00
// speak actions
2015-03-06 13:00:02 +00:00
# ifdef HAVE_SPEECH
2015-10-29 12:37:11 +00:00
d - > aSpeakDoc = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " text-speak " ) ) , i18n ( " Speak Whole Document " ) , this ) ;
ac - > addAction ( QStringLiteral ( " speak_document " ) , d - > aSpeakDoc ) ;
2008-08-04 10:16:47 +00:00
d - > aSpeakDoc - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aSpeakDoc , & QAction : : triggered , this , & PageView : : slotSpeakDocument ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
d - > aSpeakPage = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " text-speak " ) ) , i18n ( " Speak Current Page " ) , this ) ;
ac - > addAction ( QStringLiteral ( " speak_current_page " ) , d - > aSpeakPage ) ;
2008-08-04 10:16:47 +00:00
d - > aSpeakPage - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aSpeakPage , & QAction : : triggered , this , & PageView : : slotSpeakCurrentPage ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
d - > aSpeakStop = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " media-playback-stop " ) ) , i18n ( " Stop Speaking " ) , this ) ;
ac - > addAction ( QStringLiteral ( " speak_stop_all " ) , d - > aSpeakStop ) ;
2008-03-05 12:05:48 +00:00
d - > aSpeakStop - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > aSpeakStop , & QAction : : triggered , this , & PageView : : slotStopSpeaks ) ;
2020-07-10 22:15:05 +00:00
2019-09-19 19:50:58 +00:00
d - > aSpeakPauseResume = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " media-playback-pause " ) ) , i18n ( " Pause/Resume Speaking " ) , this ) ;
ac - > addAction ( QStringLiteral ( " speak_pause_resume " ) , d - > aSpeakPauseResume ) ;
d - > aSpeakPauseResume - > setEnabled ( false ) ;
connect ( d - > aSpeakPauseResume , & QAction : : triggered , this , & PageView : : slotPauseResumeSpeech ) ;
2015-03-06 13:00:02 +00:00
# else
2020-02-19 15:12:21 +00:00
d - > aSpeakDoc = nullptr ;
d - > aSpeakPage = nullptr ;
d - > aSpeakStop = nullptr ;
d - > aSpeakPauseResume = nullptr ;
2015-03-06 13:00:02 +00:00
# endif
2008-03-05 12:05:48 +00:00
2004-09-26 23:39:39 +00:00
// Other actions
2014-08-13 10:45:40 +00:00
QAction * su = new QAction ( i18n ( " Scroll Up " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_scroll_up " ) , su ) ;
connect ( su , & QAction : : triggered , this , & PageView : : slotAutoScrollUp ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( su , QKeySequence ( Qt : : SHIFT | Qt : : Key_Up ) ) ;
2006-09-29 09:02:07 +00:00
addAction ( su ) ;
2004-10-06 00:05:49 +00:00
2014-08-13 10:45:40 +00:00
QAction * sd = new QAction ( i18n ( " Scroll Down " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_scroll_down " ) , sd ) ;
connect ( sd , & QAction : : triggered , this , & PageView : : slotAutoScrollDown ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( sd , QKeySequence ( Qt : : SHIFT | Qt : : Key_Down ) ) ;
2006-09-29 09:02:07 +00:00
addAction ( sd ) ;
2007-02-25 00:07:59 +00:00
2014-08-13 10:45:40 +00:00
QAction * spu = new QAction ( i18n ( " Scroll Page Up " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_scroll_page_up " ) , spu ) ;
connect ( spu , & QAction : : triggered , this , & PageView : : slotScrollUp ) ;
2020-12-09 07:34:49 +00:00
ac - > setDefaultShortcut ( spu , QKeySequence ( Qt : : SHIFT | Qt : : Key_Space ) ) ;
2012-09-05 20:12:11 +00:00
addAction ( spu ) ;
2014-08-13 10:45:40 +00:00
QAction * spd = new QAction ( i18n ( " Scroll Page Down " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_scroll_page_down " ) , spd ) ;
connect ( spd , & QAction : : triggered , this , & PageView : : slotScrollDown ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( spd , QKeySequence ( Qt : : Key_Space ) ) ;
2012-09-05 20:12:11 +00:00
addAction ( spd ) ;
2020-06-26 20:20:20 +00:00
d - > aToggleForms = new KToggleAction ( i18n ( " Show Forms " ) , this ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " view_toggle_forms " ) , d - > aToggleForms ) ;
2020-06-26 20:20:20 +00:00
connect ( d - > aToggleForms , & QAction : : toggled , this , & PageView : : slotToggleForms ) ;
2007-08-28 12:04:18 +00:00
d - > aToggleForms - > setEnabled ( false ) ;
2007-02-25 00:07:59 +00:00
toggleFormWidgets ( false ) ;
2013-04-05 22:22:48 +00:00
// Setup undo and redo actions
2014-08-10 12:08:47 +00:00
QAction * kundo = KStandardAction : : create ( KStandardAction : : Undo , d - > document , SLOT ( undo ( ) ) , ac ) ;
QAction * kredo = KStandardAction : : create ( KStandardAction : : Redo , d - > document , SLOT ( redo ( ) ) , ac ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > document , & Okular : : Document : : canUndoChanged , kundo , & QAction : : setEnabled ) ;
connect ( d - > document , & Okular : : Document : : canRedoChanged , kredo , & QAction : : setEnabled ) ;
2013-04-05 22:22:48 +00:00
kundo - > setEnabled ( false ) ;
kredo - > setEnabled ( false ) ;
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
if ( ! d - > annotator ) {
d - > annotator = new PageViewAnnotator ( this , d - > document ) ;
connect ( d - > annotator , & PageViewAnnotator : : toolSelected , d - > aMouseNormal , & QAction : : trigger ) ;
2020-09-07 10:01:11 +00:00
connect ( d - > annotator , & PageViewAnnotator : : toolSelected , d - > mouseAnnotation , & MouseAnnotation : : reset ) ;
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
}
d - > annotator - > setupActions ( ac ) ;
2004-09-26 23:39:39 +00:00
}
2006-11-19 13:50:41 +00:00
bool PageView : : canFitPageWidth ( ) const
2005-01-10 13:43:44 +00:00
{
2010-01-10 01:19:16 +00:00
return Okular : : Settings : : viewMode ( ) ! = Okular : : Settings : : EnumViewMode : : Single | | d - > zoomMode ! = ZoomFitWidth ;
2005-01-10 13:43:44 +00:00
}
2005-01-09 23:37:07 +00:00
void PageView : : fitPageWidth ( int page )
2004-12-04 23:23:18 +00:00
{
2005-01-09 23:37:07 +00:00
// zoom: Fit Width, columns: 1. setActions + relayout + setPage + update
2004-12-04 23:23:18 +00:00
d - > zoomMode = ZoomFitWidth ;
2007-05-17 20:46:16 +00:00
Okular : : Settings : : setViewMode ( 0 ) ;
2004-12-04 23:23:18 +00:00
d - > aZoomFitWidth - > setChecked ( true ) ;
d - > aZoomFitPage - > setChecked ( false ) ;
2013-08-18 15:19:20 +00:00
d - > aZoomAutoFit - > setChecked ( false ) ;
2020-03-12 21:03:47 +00:00
updateViewMode ( 0 ) ;
2004-12-04 23:23:18 +00:00
viewport ( ) - > setUpdatesEnabled ( false ) ;
slotRelayoutPages ( ) ;
viewport ( ) - > setUpdatesEnabled ( true ) ;
2005-01-09 23:37:07 +00:00
d - > document - > setViewportPage ( page ) ;
2005-01-10 13:43:44 +00:00
updateZoomText ( ) ;
2005-06-13 10:22:37 +00:00
setFocus ( ) ;
2004-12-04 23:23:18 +00:00
}
2012-01-17 22:46:37 +00:00
void PageView : : openAnnotationWindow ( Okular : : Annotation * annotation , int pageNumber )
2006-08-08 15:31:13 +00:00
{
2006-12-30 12:40:54 +00:00
if ( ! annotation )
2006-08-08 15:31:13 +00:00
return ;
2006-12-30 12:40:54 +00:00
// find the annot window
2017-09-05 21:27:18 +00:00
AnnotWindow * existWindow = nullptr ;
2019-12-09 13:39:47 +00:00
for ( AnnotWindow * aw : qAsConst ( d - > m_annowindows ) ) {
2017-10-25 12:59:17 +00:00
if ( aw - > annotation ( ) = = annotation ) {
existWindow = aw ;
break ;
}
2006-08-08 15:31:13 +00:00
}
2006-12-30 12:40:54 +00:00
2017-09-05 21:27:18 +00:00
if ( existWindow = = nullptr ) {
2012-01-17 22:46:37 +00:00
existWindow = new AnnotWindow ( this , annotation , d - > document , pageNumber ) ;
2015-10-29 12:37:11 +00:00
connect ( existWindow , & QObject : : destroyed , this , & PageView : : slotAnnotationWindowDestroyed ) ;
2006-12-30 12:40:54 +00:00
2017-10-25 12:59:17 +00:00
d - > m_annowindows < < existWindow ;
2018-05-18 12:52:40 +00:00
} else {
existWindow - > raise ( ) ;
existWindow - > findChild < KTextEdit * > ( ) - > setFocus ( ) ;
2006-08-08 15:31:13 +00:00
}
2006-12-30 12:40:54 +00:00
existWindow - > show ( ) ;
}
2012-01-17 22:46:37 +00:00
void PageView : : slotAnnotationWindowDestroyed ( QObject * window )
2006-12-30 12:40:54 +00:00
{
2017-10-25 12:59:17 +00:00
d - > m_annowindows . remove ( static_cast < AnnotWindow * > ( window ) ) ;
2006-08-08 15:31:13 +00:00
}
2010-08-21 15:47:33 +00:00
void PageView : : displayMessage ( const QString & message , const QString & details , PageViewMessage : : Icon icon , int duration )
2005-03-04 23:06:24 +00:00
{
2006-09-21 08:45:36 +00:00
if ( ! Okular : : Settings : : showOSD ( ) ) {
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
if ( icon = = PageViewMessage : : Error ) {
2010-08-21 22:31:26 +00:00
if ( ! details . isEmpty ( ) )
KMessageBox : : detailedError ( this , message , details ) ;
else
KMessageBox : : error ( this , message ) ;
}
return ;
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
}
2005-03-04 23:06:24 +00:00
// hide messageWindow if string is empty
2020-02-20 17:45:46 +00:00
if ( message . isEmpty ( ) ) {
d - > messageWindow - > hide ( ) ;
return ;
}
2005-03-04 23:06:24 +00:00
2018-11-14 19:12:15 +00:00
// display message (duration is length dependent)
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
if ( duration = = - 1 ) {
duration = 500 + 100 * message . length ( ) ;
2010-08-21 15:47:33 +00:00
if ( ! details . isEmpty ( ) )
duration + = 500 + 100 * details . length ( ) ;
}
d - > messageWindow - > display ( message , details , icon , duration ) ;
2005-03-04 23:06:24 +00:00
}
2006-10-28 22:58:05 +00:00
void PageView : : reparseConfig ( )
{
2020-09-21 20:11:59 +00:00
// set smooth scrolling policies
PageView : : updateSmoothScrollAnimationSpeed ( ) ;
2006-10-28 22:58:05 +00:00
// set the scroll bars policies
Qt : : ScrollBarPolicy scrollBarMode = Okular : : Settings : : showScrollBars ( ) ? Qt : : ScrollBarAsNeeded : Qt : : ScrollBarAlwaysOff ;
if ( horizontalScrollBarPolicy ( ) ! = scrollBarMode ) {
setHorizontalScrollBarPolicy ( scrollBarMode ) ;
setVerticalScrollBarPolicy ( scrollBarMode ) ;
}
2010-01-10 01:19:16 +00:00
if ( Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : Summary & & ( ( int ) Okular : : Settings : : viewColumns ( ) ! = d - > setting_viewCols ) ) {
2007-05-19 10:19:25 +00:00
d - > setting_viewCols = Okular : : Settings : : viewColumns ( ) ;
2006-10-28 22:58:05 +00:00
slotRelayoutPages ( ) ;
}
2011-09-07 22:43:30 +00:00
2016-07-25 23:37:54 +00:00
if ( Okular : : Settings : : rtlReadingDirection ( ) ! = d - > rtl_Mode ) {
d - > rtl_Mode = Okular : : Settings : : rtlReadingDirection ( ) ;
slotRelayoutPages ( ) ;
}
2011-09-07 22:43:30 +00:00
updatePageStep ( ) ;
2012-06-09 21:52:31 +00:00
if ( d - > annotator )
d - > annotator - > reparseConfig ( ) ;
2013-04-18 23:17:56 +00:00
2012-12-31 11:04:23 +00:00
// Something like invert colors may have changed
// As we don't have a way to find out the old value
// We just update the viewport, this shouldn't be that bad
// since it's just a repaint of pixmaps we already have
viewport ( ) - > update ( ) ;
2006-10-28 22:58:05 +00:00
}
2013-05-28 21:55:10 +00:00
KActionCollection * PageView : : actionCollection ( ) const
{
return d - > actionCollection ;
}
2014-08-13 10:45:40 +00:00
QAction * PageView : : toggleFormsAction ( ) const
2007-02-25 00:07:59 +00:00
{
return d - > aToggleForms ;
}
2009-06-29 20:55:50 +00:00
int PageView : : contentAreaWidth ( ) const
{
return horizontalScrollBar ( ) - > maximum ( ) + viewport ( ) - > width ( ) ;
}
int PageView : : contentAreaHeight ( ) const
{
return verticalScrollBar ( ) - > maximum ( ) + viewport ( ) - > height ( ) ;
}
QPoint PageView : : contentAreaPosition ( ) const
{
return QPoint ( horizontalScrollBar ( ) - > value ( ) , verticalScrollBar ( ) - > value ( ) ) ;
}
2020-02-20 17:45:46 +00:00
QPoint PageView : : contentAreaPoint ( const QPoint pos ) const
2009-06-29 20:55:50 +00:00
{
return pos + contentAreaPosition ( ) ;
}
2020-02-20 17:45:46 +00:00
QPointF PageView : : contentAreaPoint ( const QPointF pos ) const
2012-10-15 18:11:47 +00:00
{
return pos + contentAreaPosition ( ) ;
}
2008-02-26 20:54:31 +00:00
QString PageViewPrivate : : selectedText ( ) const
2006-11-24 21:02:38 +00:00
{
2008-02-26 20:54:31 +00:00
if ( pagesWithTextSelection . isEmpty ( ) )
return QString ( ) ;
2006-11-24 21:02:38 +00:00
QString text ;
2019-12-20 12:32:49 +00:00
QList < int > selpages = pagesWithTextSelection . values ( ) ;
2019-03-12 12:13:53 +00:00
std : : sort ( selpages . begin ( ) , selpages . end ( ) ) ;
2017-09-05 21:27:18 +00:00
const Okular : : Page * pg = nullptr ;
2006-11-24 21:02:38 +00:00
if ( selpages . count ( ) = = 1 ) {
2008-02-26 20:54:31 +00:00
pg = document - > page ( selpages . first ( ) ) ;
2009-11-12 21:57:00 +00:00
text . append ( pg - > text ( pg - > textSelection ( ) , Okular : : TextPage : : CentralPixelTextAreaInclusionBehaviour ) ) ;
2006-11-24 21:02:38 +00:00
} else {
2008-02-26 20:54:31 +00:00
pg = document - > page ( selpages . first ( ) ) ;
2009-11-12 21:57:00 +00:00
text . append ( pg - > text ( pg - > textSelection ( ) , Okular : : TextPage : : CentralPixelTextAreaInclusionBehaviour ) ) ;
2006-11-24 21:02:38 +00:00
int end = selpages . count ( ) - 1 ;
for ( int i = 1 ; i < end ; + + i ) {
2008-02-26 20:54:31 +00:00
pg = document - > page ( selpages . at ( i ) ) ;
2017-09-05 21:27:18 +00:00
text . append ( pg - > text ( nullptr , Okular : : TextPage : : CentralPixelTextAreaInclusionBehaviour ) ) ;
2006-11-24 21:02:38 +00:00
}
2008-02-26 20:54:31 +00:00
pg = document - > page ( selpages . last ( ) ) ;
2009-11-12 21:57:00 +00:00
text . append ( pg - > text ( pg - > textSelection ( ) , Okular : : TextPage : : CentralPixelTextAreaInclusionBehaviour ) ) ;
2006-11-24 21:02:38 +00:00
}
2008-02-26 20:54:31 +00:00
return text ;
}
void PageView : : copyTextSelection ( ) const
{
const QString text = d - > selectedText ( ) ;
2006-11-24 21:02:38 +00:00
if ( ! text . isEmpty ( ) ) {
QClipboard * cb = QApplication : : clipboard ( ) ;
cb - > setText ( text , QClipboard : : Clipboard ) ;
}
}
2007-09-03 21:35:05 +00:00
void PageView : : selectAll ( )
{
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * item : qAsConst ( d - > items ) ) {
Okular : : RegularAreaRect * area = textSelectionForItem ( item ) ;
d - > pagesWithTextSelection . insert ( item - > pageNumber ( ) ) ;
d - > document - > setPageTextSelection ( item - > pageNumber ( ) , area , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) ) ;
2007-09-03 21:35:05 +00:00
}
}
2017-10-26 07:47:18 +00:00
void PageView : : createAnnotationsVideoWidgets ( PageViewItem * item , const QLinkedList < Okular : : Annotation * > & annotations )
{
qDeleteAll ( item - > videoWidgets ( ) ) ;
item - > videoWidgets ( ) . clear ( ) ;
2019-03-26 22:37:30 +00:00
for ( Okular : : Annotation * a : annotations ) {
2017-10-26 07:47:18 +00:00
if ( a - > subType ( ) = = Okular : : Annotation : : AMovie ) {
Okular : : MovieAnnotation * movieAnn = static_cast < Okular : : MovieAnnotation * > ( a ) ;
VideoWidget * vw = new VideoWidget ( movieAnn , movieAnn - > movie ( ) , d - > document , viewport ( ) ) ;
item - > videoWidgets ( ) . insert ( movieAnn - > movie ( ) , vw ) ;
vw - > pageInitialized ( ) ;
} else if ( a - > subType ( ) = = Okular : : Annotation : : ARichMedia ) {
Okular : : RichMediaAnnotation * richMediaAnn = static_cast < Okular : : RichMediaAnnotation * > ( a ) ;
VideoWidget * vw = new VideoWidget ( richMediaAnn , richMediaAnn - > movie ( ) , d - > document , viewport ( ) ) ;
item - > videoWidgets ( ) . insert ( richMediaAnn - > movie ( ) , vw ) ;
vw - > pageInitialized ( ) ;
} else if ( a - > subType ( ) = = Okular : : Annotation : : AScreen ) {
const Okular : : ScreenAnnotation * screenAnn = static_cast < Okular : : ScreenAnnotation * > ( a ) ;
Okular : : Movie * movie = GuiUtils : : renditionMovieFromScreenAnnotation ( screenAnn ) ;
if ( movie ) {
VideoWidget * vw = new VideoWidget ( screenAnn , movie , d - > document , viewport ( ) ) ;
item - > videoWidgets ( ) . insert ( movie , vw ) ;
vw - > pageInitialized ( ) ;
}
}
}
}
2005-01-09 23:37:07 +00:00
// BEGIN DocumentObserver inherited methods
2007-09-09 10:50:36 +00:00
void PageView : : notifySetup ( const QVector < Okular : : Page * > & pageSet , int setupFlags )
2004-10-10 13:21:30 +00:00
{
2007-09-09 10:50:36 +00:00
bool documentChanged = setupFlags & Okular : : DocumentObserver : : DocumentChanged ;
2014-09-09 15:22:34 +00:00
const bool allowfillforms = d - > document - > isAllowed ( Okular : : AllowFillForms ) ;
2004-10-10 13:21:30 +00:00
// reuse current pages if nothing new
2007-09-09 10:50:36 +00:00
if ( ( pageSet . count ( ) = = d - > items . count ( ) ) & & ! documentChanged & & ! ( setupFlags & Okular : : DocumentObserver : : NewLayoutForPages ) ) {
2004-10-10 13:21:30 +00:00
int count = pageSet . count ( ) ;
for ( int i = 0 ; ( i < count ) & & ! documentChanged ; i + + ) {
2004-11-05 00:14:00 +00:00
if ( ( int ) pageSet [ i ] - > number ( ) ! = d - > items [ i ] - > pageNumber ( ) ) {
2004-10-10 13:21:30 +00:00
documentChanged = true ;
2014-09-09 15:22:34 +00:00
} else {
// even if the document has not changed, allowfillforms may have
// changed, so update all fields' "canBeFilled" flag
2019-12-09 13:39:47 +00:00
const QSet < FormWidgetIface * > formWidgetsList = d - > items [ i ] - > formWidgets ( ) ;
for ( FormWidgetIface * w : formWidgetsList )
2014-09-09 15:22:34 +00:00
w - > setCanBeFilled ( allowfillforms ) ;
}
}
2017-10-26 07:47:18 +00:00
2004-10-10 13:21:30 +00:00
if ( ! documentChanged ) {
2017-10-26 07:47:18 +00:00
if ( setupFlags & Okular : : DocumentObserver : : UrlChanged ) {
// Here with UrlChanged and no document changed it means we
// need to update all the Annotation* and Form* otherwise
// they still point to the old document ones, luckily the old ones are still
// around so we can look for the new ones using unique ids, etc
d - > mouseAnnotation - > updateAnnotationPointers ( ) ;
2019-12-09 13:39:47 +00:00
for ( AnnotWindow * aw : qAsConst ( d - > m_annowindows ) ) {
2017-10-26 07:47:18 +00:00
Okular : : Annotation * newA = d - > document - > page ( aw - > pageNumber ( ) ) - > annotation ( aw - > annotation ( ) - > uniqueName ( ) ) ;
aw - > updateAnnotation ( newA ) ;
}
const QRect viewportRect ( horizontalScrollBar ( ) - > value ( ) , verticalScrollBar ( ) - > value ( ) , viewport ( ) - > width ( ) , viewport ( ) - > height ( ) ) ;
for ( int i = 0 ; i < count ; i + + ) {
PageViewItem * item = d - > items [ i ] ;
const QSet < FormWidgetIface * > fws = item - > formWidgets ( ) ;
2019-12-09 13:39:47 +00:00
for ( FormWidgetIface * w : fws ) {
2017-10-26 07:47:18 +00:00
Okular : : FormField * f = Okular : : PagePrivate : : findEquivalentForm ( d - > document - > page ( i ) , w - > formField ( ) ) ;
if ( f ) {
w - > setFormField ( f ) ;
} else {
qWarning ( ) < < " Lost form field on document save, something is wrong " ;
item - > formWidgets ( ) . remove ( w ) ;
delete w ;
}
}
// For the video widgets we don't really care about reusing them since they don't contain much info so just
// create them again
createAnnotationsVideoWidgets ( item , pageSet [ i ] - > annotations ( ) ) ;
2019-12-09 13:39:47 +00:00
const QHash < Okular : : Movie * , VideoWidget * > videoWidgets = item - > videoWidgets ( ) ;
for ( VideoWidget * vw : videoWidgets ) {
2017-10-26 07:47:18 +00:00
const Okular : : NormalizedRect r = vw - > normGeometry ( ) ;
vw - > setGeometry ( qRound ( item - > uncroppedGeometry ( ) . left ( ) + item - > uncroppedWidth ( ) * r . left ) + 1 - viewportRect . left ( ) ,
qRound ( item - > uncroppedGeometry ( ) . top ( ) + item - > uncroppedHeight ( ) * r . top ) + 1 - viewportRect . top ( ) ,
qRound ( fabs ( r . right - r . left ) * item - > uncroppedGeometry ( ) . width ( ) ) ,
qRound ( fabs ( r . bottom - r . top ) * item - > uncroppedGeometry ( ) . height ( ) ) ) ;
// Workaround, otherwise the size somehow gets lost
vw - > show ( ) ;
vw - > hide ( ) ;
}
}
}
2004-10-10 13:21:30 +00:00
return ;
2017-10-26 07:47:18 +00:00
}
2004-10-10 13:21:30 +00:00
}
2008-11-21 10:50:16 +00:00
2017-04-13 17:17:56 +00:00
// mouseAnnotation must not access our PageViewItem widgets any longer
d - > mouseAnnotation - > reset ( ) ;
2004-10-10 13:21:30 +00:00
// delete all widgets (one for each page in pageSet)
2019-03-26 22:37:30 +00:00
qDeleteAll ( d - > items ) ;
2004-11-05 00:14:00 +00:00
d - > items . clear ( ) ;
2005-01-03 01:10:27 +00:00
d - > visibleItems . clear ( ) ;
2007-12-31 18:28:02 +00:00
d - > pagesWithTextSelection . clear ( ) ;
2007-02-25 00:07:59 +00:00
toggleFormWidgets ( false ) ;
2008-02-11 10:41:04 +00:00
if ( d - > formsWidgetController )
d - > formsWidgetController - > dropRadioButtons ( ) ;
2004-09-26 23:39:39 +00:00
2007-08-28 12:04:18 +00:00
bool haspages = ! pageSet . isEmpty ( ) ;
2007-02-25 00:07:59 +00:00
bool hasformwidgets = false ;
2004-09-26 23:39:39 +00:00
// create children widgets
2019-03-26 22:37:30 +00:00
for ( const Okular : : Page * page : pageSet ) {
PageViewItem * item = new PageViewItem ( page ) ;
2007-02-25 00:07:59 +00:00
d - > items . push_back ( item ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) . nospace ( ) < < " cropped geom for " < < d - > items . last ( ) - > pageNumber ( ) < < " is " < < d - > items . last ( ) - > croppedGeometry ( ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# endif
2019-03-26 22:37:30 +00:00
const QLinkedList < Okular : : FormField * > pageFields = page - > formFields ( ) ;
for ( Okular : : FormField * ff : pageFields ) {
2009-06-29 20:55:50 +00:00
FormWidgetIface * w = FormWidgetFactory : : createWidget ( ff , viewport ( ) ) ;
2007-02-25 00:07:59 +00:00
if ( w ) {
2007-10-18 22:09:49 +00:00
w - > setPageItem ( item ) ;
w - > setFormWidgetsController ( d - > formWidgetsController ( ) ) ;
2007-12-31 22:22:38 +00:00
w - > setVisibility ( false ) ;
2014-09-09 15:22:34 +00:00
w - > setCanBeFilled ( allowfillforms ) ;
2017-10-25 12:51:58 +00:00
item - > formWidgets ( ) . insert ( w ) ;
2007-02-25 00:07:59 +00:00
hasformwidgets = true ;
}
}
2017-10-26 07:47:18 +00:00
2019-03-26 22:37:30 +00:00
createAnnotationsVideoWidgets ( item , page - > annotations ( ) ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
}
2004-09-26 23:39:39 +00:00
2005-01-09 23:37:07 +00:00
// invalidate layout so relayout/repaint will happen on next viewport change
2007-08-28 12:04:18 +00:00
if ( haspages ) {
2010-01-09 15:37:38 +00:00
// We do a delayed call to slotRelayoutPages but also set the dirtyLayout
// because we might end up in notifyViewportChanged while slotRelayoutPages
// has not been done and we don't want that to happen
d - > dirtyLayout = true ;
2011-03-17 15:24:44 +00:00
QMetaObject : : invokeMethod ( this , " slotRelayoutPages " , Qt : : QueuedConnection ) ;
2005-01-27 17:31:07 +00:00
} else {
2005-11-04 11:59:51 +00:00
// update the mouse cursor when closing because we may have close through a link and
// want the cursor to come back to the normal cursor
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2011-12-07 22:05:36 +00:00
// then, make the message window and scrollbars disappear, and trigger a repaint
2011-10-18 20:36:42 +00:00
d - > messageWindow - > hide ( ) ;
resizeContentArea ( QSize ( 0 , 0 ) ) ;
2011-12-07 22:05:36 +00:00
viewport ( ) - > update ( ) ; // when there is no change to the scrollbars, no repaint would
// be done and the old document would still be shown
2005-11-04 11:59:51 +00:00
}
2004-10-29 20:20:21 +00:00
// OSD to display pages
2006-09-21 08:45:36 +00:00
if ( documentChanged & & pageSet . count ( ) > 0 & & Okular : : Settings : : showOSD ( ) )
2006-04-10 18:50:27 +00:00
d - > messageWindow - > display ( i18np ( " Loaded a one-page document. " , " Loaded a %1-page document. " , pageSet . count ( ) ) , QString ( ) , PageViewMessage : : Info , 4000 ) ;
2005-07-20 22:28:23 +00:00
2020-05-24 16:54:32 +00:00
updateActionState ( haspages , hasformwidgets ) ;
2011-10-23 09:17:04 +00:00
2012-03-07 22:51:36 +00:00
// We need to assign it to a different list otherwise slotAnnotationWindowDestroyed
// will bite us and clear d->m_annowindows
2017-10-25 12:59:17 +00:00
QSet < AnnotWindow * > annowindows = d - > m_annowindows ;
2011-10-23 09:17:04 +00:00
d - > m_annowindows . clear ( ) ;
2012-03-07 22:51:36 +00:00
qDeleteAll ( annowindows ) ;
2011-10-23 09:17:04 +00:00
selectionClear ( ) ;
}
2020-05-24 16:54:32 +00:00
void PageView : : updateActionState ( bool haspages , bool hasformwidgets )
2011-10-23 09:17:04 +00:00
{
if ( d - > aTrimMargins )
d - > aTrimMargins - > setEnabled ( haspages ) ;
2015-08-27 20:09:02 +00:00
if ( d - > aTrimToSelection )
d - > aTrimToSelection - > setEnabled ( haspages ) ;
2020-03-12 21:03:47 +00:00
if ( d - > aViewModeMenu )
d - > aViewModeMenu - > setEnabled ( haspages ) ;
2011-10-23 09:17:04 +00:00
if ( d - > aViewContinuous )
d - > aViewContinuous - > setEnabled ( haspages ) ;
if ( d - > aZoomFitWidth )
d - > aZoomFitWidth - > setEnabled ( haspages ) ;
if ( d - > aZoomFitPage )
d - > aZoomFitPage - > setEnabled ( haspages ) ;
2014-02-16 17:09:15 +00:00
if ( d - > aZoomAutoFit )
d - > aZoomAutoFit - > setEnabled ( haspages ) ;
2011-10-23 09:17:04 +00:00
2011-11-24 21:28:07 +00:00
if ( d - > aZoom ) {
d - > aZoom - > selectableActionGroup ( ) - > setEnabled ( haspages ) ;
d - > aZoom - > setEnabled ( haspages ) ;
}
2011-10-23 09:17:04 +00:00
if ( d - > aZoomIn )
d - > aZoomIn - > setEnabled ( haspages ) ;
if ( d - > aZoomOut )
d - > aZoomOut - > setEnabled ( haspages ) ;
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
if ( d - > aZoomActual )
d - > aZoomActual - > setEnabled ( haspages & & d - > zoomFactor ! = 1.0 ) ;
2020-07-10 22:15:05 +00:00
2020-07-14 10:03:47 +00:00
if ( d - > aReadingDirection ) {
d - > aReadingDirection - > setEnabled ( haspages ) ;
}
2011-10-23 09:17:04 +00:00
if ( d - > mouseModeActionGroup )
d - > mouseModeActionGroup - > setEnabled ( haspages ) ;
Replace ToolAction by ToggleActionMenu
Summary:
This replaces ToolAction by a near-drop-in replacement named ToggleActionMenu. The new annotation toolbar already uses this (D15580).
Unlike ToolAction, ToggleActionMenu inherits from KActionMenu to be more flexible.
* Menu can be set from outside, not hard coded.
* Default action for toolbar button is controllable from outside. (Theoretically, the button could trigger //anything// now.)
* KActionMenu instead of KSelectAction:
- Pluggable in other menus, thus called “Menu”.
- Doesn’t make the actions exclusive, so //any// actions can be added to the menu.
* ImplicitDefaultAction mode can choose the default action of the toolbar buttons automatically, by looking for the first checked action in the menu.
Toolbar buttons use the default action //of// this menu, not this menu itself as action.
Because the default action is configurable now, D21622 and D21635 (where we tried to fine-tune ToolAction) become obsolete.
Screenshot:
Everything like before, here with mouse_selecttool added to Tools menu to show submenu capability.
{F6884228}
Test Plan:
ToolAction replacement and ImplicitDefaultAction mode:
* Open Okular and look at toolbar button -> has correct tool selected.
* Open a document.
* Look at toolbar button menu -> Correct menu entries (like before, with ToolAction).
* Select some selection tools through shortcuts and toolbar button -> behaves correctly.
Usage as submenu:
* Add ToggleActionMenu ("mouse_selecttool") to menubar (..../kxmlgui5/okular/part.rc) -> Submenu looks correctly, has no checkbox attached and so on...
Toolbar buttons:
* Add diverse other actions to the menu -> still works as before.
* Add actions when toolbar buttons are already created -> actions are added to existing buttons.
* setDefaultAction() to some completely unrelated action. -> ToggleActionMenu does not get confused.
Reviewers: simgunz
Reviewed By: simgunz
Subscribers: aacid, ngraham, simgunz, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D21971
2020-02-01 18:54:18 +00:00
if ( d - > aMouseModeMenu )
d - > aMouseModeMenu - > setEnabled ( haspages ) ;
2020-07-10 22:15:05 +00:00
2007-08-28 12:04:18 +00:00
if ( d - > aRotateClockwise )
d - > aRotateClockwise - > setEnabled ( haspages ) ;
if ( d - > aRotateCounterClockwise )
d - > aRotateCounterClockwise - > setEnabled ( haspages ) ;
if ( d - > aRotateOriginal )
d - > aRotateOriginal - > setEnabled ( haspages ) ;
2007-06-05 20:49:00 +00:00
if ( d - > aToggleForms ) { // may be null if dummy mode is on
2007-08-28 12:04:18 +00:00
d - > aToggleForms - > setEnabled ( haspages & & hasformwidgets ) ;
2007-01-05 23:12:06 +00:00
}
2007-08-27 22:11:18 +00:00
bool allowAnnotations = d - > document - > isAllowed ( Okular : : AllowNotes ) ;
2007-04-30 17:40:53 +00:00
if ( d - > annotator ) {
2007-12-09 01:35:42 +00:00
bool allowTools = haspages & & allowAnnotations ;
d - > annotator - > setToolsEnabled ( allowTools ) ;
d - > annotator - > setTextToolsEnabled ( allowTools & & d - > document - > supportsSearching ( ) ) ;
}
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-08-04 10:16:47 +00:00
if ( d - > aSpeakDoc ) {
2014-11-08 04:33:23 +00:00
const bool enablettsactions = haspages ? Okular : : Settings : : useTTS ( ) : false ;
2008-08-04 10:16:47 +00:00
d - > aSpeakDoc - > setEnabled ( enablettsactions ) ;
d - > aSpeakPage - > setEnabled ( enablettsactions ) ;
}
2014-11-08 04:33:23 +00:00
# endif
2014-03-02 12:59:33 +00:00
if ( d - > aMouseMagnifier )
2014-03-02 23:43:14 +00:00
d - > aMouseMagnifier - > setEnabled ( d - > document - > supportsTiles ( ) ) ;
2015-03-16 23:20:11 +00:00
if ( d - > aFitWindowToPage )
d - > aFitWindowToPage - > setEnabled ( haspages & & ! Okular : : Settings : : viewContinuous ( ) ) ;
2004-09-26 23:39:39 +00:00
}
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
void PageView : : setupActionsPostGUIActivated ( )
{
d - > annotator - > setupActionsPostGUIActivated ( ) ;
}
2011-11-07 21:07:10 +00:00
bool PageView : : areSourceLocationsShownGraphically ( ) const
{
return Okular : : Settings : : showSourceLocationsGraphically ( ) ;
}
void PageView : : setShowSourceLocationsGraphically ( bool show )
{
if ( show = = Okular : : Settings : : showSourceLocationsGraphically ( ) ) {
return ;
}
Okular : : Settings : : setShowSourceLocationsGraphically ( show ) ;
viewport ( ) - > update ( ) ;
}
2011-11-01 21:13:20 +00:00
void PageView : : setLastSourceLocationViewport ( const Okular : : DocumentViewport & vp )
{
if ( vp . rePos . enabled ) {
d - > lastSourceLocationViewportNormalizedX = normClamp ( vp . rePos . normalizedX , 0.5 ) ;
d - > lastSourceLocationViewportNormalizedY = normClamp ( vp . rePos . normalizedY , 0.0 ) ;
} else {
d - > lastSourceLocationViewportNormalizedX = 0.5 ;
d - > lastSourceLocationViewportNormalizedY = 0.0 ;
}
d - > lastSourceLocationViewportPageNumber = vp . pageNumber ;
2011-11-07 21:07:10 +00:00
viewport ( ) - > update ( ) ;
2011-11-01 21:13:20 +00:00
}
2011-11-05 09:18:08 +00:00
void PageView : : clearLastSourceLocationViewport ( )
{
d - > lastSourceLocationViewportPageNumber = - 1 ;
d - > lastSourceLocationViewportNormalizedX = 0.0 ;
d - > lastSourceLocationViewportNormalizedY = 0.0 ;
2011-11-07 21:07:10 +00:00
viewport ( ) - > update ( ) ;
2011-11-05 09:18:08 +00:00
}
2005-02-01 18:24:16 +00:00
void PageView : : notifyViewportChanged ( bool smoothMove )
2011-11-02 21:46:23 +00:00
{
QMetaObject : : invokeMethod ( this , " slotRealNotifyViewportChanged " , Qt : : QueuedConnection , Q_ARG ( bool , smoothMove ) ) ;
}
2013-04-05 22:22:48 +00:00
2011-11-02 21:46:23 +00:00
void PageView : : slotRealNotifyViewportChanged ( bool smoothMove )
2004-09-26 23:39:39 +00:00
{
2018-11-14 19:12:15 +00:00
// if we are the one changing viewport, skip this notify
2005-01-09 23:37:07 +00:00
if ( d - > blockViewport )
return ;
// block setViewport outgoing calls
d - > blockViewport = true ;
// find PageViewItem matching the viewport description
2006-09-21 08:45:36 +00:00
const Okular : : DocumentViewport & vp = d - > document - > viewport ( ) ;
2019-03-26 22:37:30 +00:00
const PageViewItem * item = nullptr ;
for ( const PageViewItem * tmpItem : qAsConst ( d - > items ) )
if ( tmpItem - > pageNumber ( ) = = vp . pageNumber ) {
item = tmpItem ;
2004-09-26 23:39:39 +00:00
break ;
}
2005-01-09 23:37:07 +00:00
if ( ! item ) {
2017-01-14 18:15:26 +00:00
qCWarning ( OkularUiDebug ) < < " viewport for page " < < vp . pageNumber < < " has no matching item! " ;
2005-11-04 11:59:51 +00:00
d - > blockViewport = false ;
2004-09-30 18:16:12 +00:00
return ;
2005-01-09 23:37:07 +00:00
}
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < " document viewport changed " ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# endif
2004-10-10 13:21:30 +00:00
// relayout in "Single Pages" mode or if a relayout is pending
2005-01-21 20:05:36 +00:00
d - > blockPixmapsRequest = true ;
2006-09-21 08:45:36 +00:00
if ( ! Okular : : Settings : : viewContinuous ( ) | | d - > dirtyLayout )
2004-09-30 18:16:12 +00:00
slotRelayoutPages ( ) ;
2005-02-01 18:24:16 +00:00
// restore viewport center or use default {x-center,v-top} alignment
Fix inconsistent viewport positioning in PageView
Summary:
This diff unifies the calculation of the viewport position from a given DocumentViewport. PageView::notifyViewportChanged and PageView::slotRelayoutPages used to handle it differntly, which resulted in viewport jumps for no reason.
It happened in various situations, e.g. when jumping to a page using the footer page navigation, or when reloading the document after presentation mode left, or when resizing the main window after presentation mode left.
The diff selects the notifyViewportChanged way (align viewport top border with page top margin) as golden behavior in case of rePos.enabled == false.
BUGS: 357958
CCBUG: 341939
CCBUG: 400890
341939 and 400890 are fixed partially. These two still suffer from a minor displacement that happens when finished signal arrives from pixmap generation thread.
Test Plan:
- When using the footer page navigation to jump to different pages, new page top is always algined with viewport top.
- After changing page with footer page navigation, press F5 to reload. Page top stays aligned with viewport top.
- When exiting presentation mode, and touching the file, page top stays aligned with viewport top.
- When exiting presentation mode, and changing main window size, page top stays aligned with viewport top.
Reviewers: #okular, sander
Reviewed By: sander
Subscribers: ngraham, sander, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16941
2018-11-22 17:50:14 +00:00
const QPoint centerCoord = viewportToContentArea ( vp ) ;
2005-02-01 18:24:16 +00:00
// if smooth movement requested, setup parameters and start it
2019-11-15 16:08:25 +00:00
center ( centerCoord . x ( ) , centerCoord . y ( ) , smoothMove ) ;
2005-01-21 20:05:36 +00:00
d - > blockPixmapsRequest = false ;
2005-01-09 23:37:07 +00:00
// request visible pixmaps in the current viewport and recompute it
2004-09-30 18:16:12 +00:00
slotRequestVisiblePixmaps ( ) ;
2005-01-09 23:37:07 +00:00
// enable setViewport calls
d - > blockViewport = false ;
2011-10-31 21:41:50 +00:00
if ( viewport ( ) ) {
viewport ( ) - > update ( ) ;
2011-09-10 17:15:52 +00:00
}
2005-01-09 23:37:07 +00:00
// since the page has moved below cursor, update it
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2004-09-26 23:39:39 +00:00
}
2004-12-21 12:38:52 +00:00
2005-01-30 00:58:16 +00:00
void PageView : : notifyPageChanged ( int pageNumber , int changedFlags )
2004-12-21 12:38:52 +00:00
{
2005-01-30 00:58:16 +00:00
// only handle pixmap / highlight changes notifies
if ( changedFlags & DocumentObserver : : Bookmark )
return ;
2004-12-21 12:38:52 +00:00
2008-03-24 00:08:08 +00:00
if ( changedFlags & DocumentObserver : : Annotations ) {
2008-05-29 19:12:56 +00:00
const QLinkedList < Okular : : Annotation * > annots = d - > document - > page ( pageNumber ) - > annotations ( ) ;
const QLinkedList < Okular : : Annotation * > : : ConstIterator annItEnd = annots . end ( ) ;
2017-10-25 12:59:17 +00:00
QSet < AnnotWindow * > : : Iterator it = d - > m_annowindows . begin ( ) ;
2008-05-29 19:12:56 +00:00
for ( ; it ! = d - > m_annowindows . end ( ) ; ) {
2019-07-23 15:30:44 +00:00
QLinkedList < Okular : : Annotation * > : : ConstIterator annIt = std : : find ( annots . begin ( ) , annots . end ( ) , ( * it ) - > annotation ( ) ) ;
2008-05-29 19:12:56 +00:00
if ( annIt ! = annItEnd ) {
( * it ) - > reloadInfo ( ) ;
+ + it ;
} else {
2012-01-17 22:46:37 +00:00
AnnotWindow * w = * it ;
2008-05-29 19:12:56 +00:00
it = d - > m_annowindows . erase ( it ) ;
2012-01-17 22:46:37 +00:00
// Need to delete after removing from the list
2013-06-24 10:46:16 +00:00
// otherwise deleting will call slotAnnotationWindowDestroyed which will mess
2012-01-17 22:46:37 +00:00
// the list and the iterators
2013-04-05 22:22:48 +00:00
delete w ;
2008-05-29 19:12:56 +00:00
}
2008-03-24 00:08:08 +00:00
}
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
Fix crash due to dangling pointer in MouseAnnotation
Summary:
BUG: 388228
Diff applies to Applications/17.12, and should be easy to merge to master. It's kept quite minimal as suggested by Albert.
Albert also suggested to add a dedicated unit test and I'd agree, but am not yet sure how to do it. The original bug involves several classes, including UI: Document, Page, AddAnnotationCommand, PageView, PageViewAnnotator, MouseAnnotation - to name a few. So a test for the exact bug scenario would become a bigger integration test rather than an isolated unit test. The other approach would be to do a real unit test on MouseAnnotation. But again, MouseAnnotation has nasty dependencies (e.g., needs a parent PageView) which I'd have to mock. Any ideas? I'd be interested in a discussion on this topic.
Test Plan:
# Load a document (e.g. [[ http://www.philipebert.info/resources/WhatMathematicalKnowledgeCouldNotBe.pdf | linked PDF from bug report ]]) and enable highlight toolbar (F6).
# Create highlight annotation.
# Move the view port so that the annotation position is right beside the highlight tool icon.
# Move the mouse over the annotation, and then horizontally left until you reach the tool icon; it's important to stay over the highlight annotation as long as in viewport.
# Press ctrl-z for undo.
# Click on highlight tool, move right into the document, create new highlight annotation.
# Okular doesn't crash.
Reviewers: #okular
Subscribers: aacid, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D9852
2018-02-25 17:13:25 +00:00
d - > mouseAnnotation - > notifyAnnotationChanged ( pageNumber ) ;
2008-03-24 00:08:08 +00:00
}
2008-05-19 00:37:14 +00:00
if ( changedFlags & DocumentObserver : : BoundingBox ) {
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < " BoundingBox change on page " < < pageNumber ;
2008-05-19 00:37:14 +00:00
# endif
slotRelayoutPages ( ) ;
slotRequestVisiblePixmaps ( ) ; // TODO: slotRelayoutPages() may have done this already!
// Repaint the whole widget since layout may have changed
2009-06-29 20:55:50 +00:00
viewport ( ) - > update ( ) ;
2008-05-19 00:37:14 +00:00
return ;
}
2005-01-09 23:37:07 +00:00
// iterate over visible items: if page(pageNumber) is one of them, repaint it
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * visibleItem : qAsConst ( d - > visibleItems ) )
if ( visibleItem - > pageNumber ( ) = = pageNumber & & visibleItem - > isVisible ( ) ) {
2004-12-21 12:38:52 +00:00
// update item's rectangle plus the little outline
2019-03-26 22:37:30 +00:00
QRect expandedRect = visibleItem - > croppedGeometry ( ) ;
2009-06-29 20:55:50 +00:00
// a PageViewItem is placed in the global page layout,
// while we need to map its position in the viewport coordinates
// (to get the correct area to repaint)
expandedRect . translate ( - contentAreaPosition ( ) ) ;
2006-03-29 16:46:09 +00:00
expandedRect . adjust ( - 1 , - 1 , 3 , 3 ) ;
2009-06-29 20:55:50 +00:00
viewport ( ) - > update ( expandedRect ) ;
2005-01-02 11:50:38 +00:00
2005-01-02 13:40:40 +00:00
// if we were "zoom-dragging" do not overwrite the "zoom-drag" cursor
2005-01-09 23:37:07 +00:00
if ( cursor ( ) . shape ( ) ! = Qt : : SizeVerCursor ) {
// since the page has been regenerated below cursor, update it
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2005-01-02 11:50:38 +00:00
}
2004-12-21 12:38:52 +00:00
break ;
}
}
2005-01-09 23:37:07 +00:00
void PageView : : notifyContentsCleared ( int changedFlags )
2004-12-21 12:38:52 +00:00
{
2005-01-09 23:37:07 +00:00
// if pixmaps were cleared, re-ask them
if ( changedFlags & DocumentObserver : : Pixmap )
2006-10-19 21:18:39 +00:00
QMetaObject : : invokeMethod ( this , " slotRequestVisiblePixmaps " , Qt : : QueuedConnection ) ;
2004-12-21 12:38:52 +00:00
}
2005-01-09 23:37:07 +00:00
2007-07-08 14:25:08 +00:00
void PageView : : notifyZoom ( int factor )
{
if ( factor > 0 )
updateZoom ( ZoomIn ) ;
else
updateZoom ( ZoomOut ) ;
}
2006-11-20 20:10:42 +00:00
bool PageView : : canUnloadPixmap ( int pageNumber ) const
2005-01-09 23:37:07 +00:00
{
2012-10-15 22:27:42 +00:00
if ( Okular : : SettingsCore : : memoryLevel ( ) = = Okular : : SettingsCore : : EnumMemoryLevel : : Low | | Okular : : SettingsCore : : memoryLevel ( ) = = Okular : : SettingsCore : : EnumMemoryLevel : : Normal ) {
2006-11-24 19:29:52 +00:00
// if the item is visible, forbid unloading
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * visibleItem : qAsConst ( d - > visibleItems ) )
if ( visibleItem - > pageNumber ( ) = = pageNumber )
2006-11-24 19:29:52 +00:00
return false ;
} else {
// forbid unloading of the visible items, and of the previous and next
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * visibleItem : qAsConst ( d - > visibleItems ) )
if ( abs ( visibleItem - > pageNumber ( ) - pageNumber ) < = 1 )
2006-11-24 19:29:52 +00:00
return false ;
}
2005-01-09 23:37:07 +00:00
// if hidden premit unloading
return true ;
}
2012-09-21 09:20:53 +00:00
void PageView : : notifyCurrentPageChanged ( int previous , int current )
{
if ( previous ! = - 1 ) {
PageViewItem * item = d - > items . at ( previous ) ;
if ( item ) {
2019-12-09 13:39:47 +00:00
const QHash < Okular : : Movie * , VideoWidget * > videoWidgetsList = item - > videoWidgets ( ) ;
for ( VideoWidget * videoWidget : videoWidgetsList )
2012-09-21 09:20:53 +00:00
videoWidget - > pageLeft ( ) ;
}
2019-05-23 13:28:53 +00:00
// On close, run the widget scripts, needed for running animated PDF
const Okular : : Page * page = d - > document - > page ( previous ) ;
2019-12-09 13:39:47 +00:00
const QLinkedList < Okular : : Annotation * > annotations = page - > annotations ( ) ;
for ( Okular : : Annotation * annotation : annotations ) {
2019-05-23 13:28:53 +00:00
if ( annotation - > subType ( ) = = Okular : : Annotation : : AWidget ) {
Okular : : WidgetAnnotation * widgetAnnotation = static_cast < Okular : : WidgetAnnotation * > ( annotation ) ;
d - > document - > processAction ( widgetAnnotation - > additionalAction ( Okular : : Annotation : : PageClosing ) ) ;
}
}
2012-09-21 09:20:53 +00:00
}
if ( current ! = - 1 ) {
PageViewItem * item = d - > items . at ( current ) ;
if ( item ) {
2019-12-09 13:39:47 +00:00
const QHash < Okular : : Movie * , VideoWidget * > videoWidgetsList = item - > videoWidgets ( ) ;
for ( VideoWidget * videoWidget : videoWidgetsList )
2012-09-21 09:20:53 +00:00
videoWidget - > pageEntered ( ) ;
}
2014-08-24 20:37:15 +00:00
// update zoom text and factor if in a ZoomFit/* zoom mode
if ( d - > zoomMode ! = ZoomFixed )
updateZoomText ( ) ;
2019-05-23 13:28:53 +00:00
// Opening any widget scripts, needed for running animated PDF
const Okular : : Page * page = d - > document - > page ( current ) ;
2019-12-09 13:39:47 +00:00
const QLinkedList < Okular : : Annotation * > annotations = page - > annotations ( ) ;
for ( Okular : : Annotation * annotation : annotations ) {
2019-05-23 13:28:53 +00:00
if ( annotation - > subType ( ) = = Okular : : Annotation : : AWidget ) {
Okular : : WidgetAnnotation * widgetAnnotation = static_cast < Okular : : WidgetAnnotation * > ( annotation ) ;
d - > document - > processAction ( widgetAnnotation - > additionalAction ( Okular : : Annotation : : PageOpening ) ) ;
}
}
2012-09-21 09:20:53 +00:00
}
2020-09-07 05:56:28 +00:00
// if the view is paged (or not continuous) and there is a selected annotation,
// we call reset to avoid creating an artifact in the next page.
if ( ! Okular : : Settings : : viewContinuous ( ) ) {
if ( d - > mouseAnnotation & & d - > mouseAnnotation - > isFocused ( ) ) {
d - > mouseAnnotation - > reset ( ) ;
}
}
2012-09-21 09:20:53 +00:00
}
2005-01-09 23:37:07 +00:00
// END DocumentObserver inherited methods
2004-09-26 23:39:39 +00:00
2008-04-27 11:17:05 +00:00
// BEGIN View inherited methods
bool PageView : : supportsCapability ( ViewCapability capability ) const
{
switch ( capability ) {
case Zoom :
2008-05-31 20:45:30 +00:00
case ZoomModality :
2019-09-18 07:40:06 +00:00
case Continuous :
case ViewModeModality :
case TrimMargins :
2008-04-27 11:17:05 +00:00
return true ;
}
return false ;
}
Okular : : View : : CapabilityFlags PageView : : capabilityFlags ( ViewCapability capability ) const
{
switch ( capability ) {
case Zoom :
2008-05-31 20:45:30 +00:00
case ZoomModality :
2019-09-18 07:40:06 +00:00
case Continuous :
case ViewModeModality :
case TrimMargins :
2008-05-31 21:08:45 +00:00
return CapabilityRead | CapabilityWrite | CapabilitySerializable ;
2008-04-27 11:17:05 +00:00
}
2019-09-18 07:50:13 +00:00
return NoFlag ;
2008-04-27 11:17:05 +00:00
}
QVariant PageView : : capability ( ViewCapability capability ) const
{
switch ( capability ) {
case Zoom :
return d - > zoomFactor ;
2008-05-31 20:45:30 +00:00
case ZoomModality :
return d - > zoomMode ;
2019-09-18 07:40:06 +00:00
case Continuous :
2019-12-28 22:28:18 +00:00
return d - > aViewContinuous ? d - > aViewContinuous - > isChecked ( ) : true ;
2019-09-18 07:40:06 +00:00
case ViewModeModality : {
2020-03-12 21:03:47 +00:00
if ( d - > viewModeActionGroup ) {
const QList < QAction * > actions = d - > viewModeActionGroup - > actions ( ) ;
for ( const QAction * action : actions ) {
if ( action - > isChecked ( ) ) {
return action - > data ( ) ;
}
2019-09-18 07:40:06 +00:00
}
}
return QVariant ( ) ;
2020-07-10 22:15:05 +00:00
}
2019-09-18 07:40:06 +00:00
case TrimMargins :
2019-12-28 22:28:18 +00:00
return d - > aTrimMargins ? d - > aTrimMargins - > isChecked ( ) : false ;
2008-04-27 11:17:05 +00:00
}
return QVariant ( ) ;
}
void PageView : : setCapability ( ViewCapability capability , const QVariant & option )
{
switch ( capability ) {
case Zoom : {
2008-05-31 20:45:30 +00:00
bool ok = true ;
double factor = option . toDouble ( & ok ) ;
2019-09-18 07:40:06 +00:00
if ( ok & & factor > 0.0 ) {
d - > zoomFactor = static_cast < float > ( factor ) ;
updateZoom ( ZoomRefreshCurrent ) ;
}
2020-07-10 22:15:05 +00:00
break ;
}
2019-09-18 07:40:06 +00:00
case ZoomModality : {
bool ok = true ;
int mode = option . toInt ( & ok ) ;
2020-07-10 22:15:05 +00:00
if ( ok ) {
2019-09-18 07:40:06 +00:00
if ( mode > = 0 & & mode < 3 )
updateZoom ( ( ZoomMode ) mode ) ;
}
2020-07-10 22:15:05 +00:00
break ;
}
2019-09-18 07:40:06 +00:00
case ViewModeModality : {
bool ok = true ;
int mode = option . toInt ( & ok ) ;
2020-07-10 22:15:05 +00:00
if ( ok ) {
2019-09-18 07:40:06 +00:00
if ( mode > = 0 & & mode < Okular : : Settings : : EnumViewMode : : COUNT )
updateViewMode ( mode ) ;
}
2020-07-10 22:15:05 +00:00
break ;
}
2012-03-09 17:43:40 +00:00
case Continuous : {
2019-09-18 07:40:06 +00:00
bool mode = option . toBool ( ) ;
d - > aViewContinuous - > setChecked ( mode ) ;
2007-05-17 20:46:16 +00:00
slotContinuousToggled ( mode ) ;
2020-07-10 22:15:05 +00:00
break ;
}
2015-08-27 20:09:02 +00:00
case TrimMargins : {
2006-10-03 17:13:42 +00:00
bool value = option . toBool ( ) ;
2019-09-18 07:40:06 +00:00
d - > aTrimMargins - > setChecked ( value ) ;
slotTrimMarginsToggled ( value ) ;
2020-07-10 22:15:05 +00:00
break ;
}
2008-04-27 11:17:05 +00:00
}
}
// END View inherited methods
2004-10-10 12:42:42 +00:00
// BEGIN widget events
2016-10-15 13:22:35 +00:00
bool PageView : : event ( QEvent * event )
{
if ( event - > type ( ) = = QEvent : : Gesture ) {
return gestureEvent ( static_cast < QGestureEvent * > ( event ) ) ;
}
// do not stop the event
return QAbstractScrollArea : : event ( event ) ;
}
bool PageView : : gestureEvent ( QGestureEvent * event )
{
QPinchGesture * pinch = static_cast < QPinchGesture * > ( event - > gesture ( Qt : : PinchGesture ) ) ;
if ( pinch ) {
// Viewport zoom level at the moment where the pinch gesture starts.
// The viewport zoom level _during_ the gesture will be this value
// times the relative zoom reported by QGestureEvent.
static qreal vanillaZoom = d - > zoomFactor ;
if ( pinch - > state ( ) = = Qt : : GestureStarted ) {
vanillaZoom = d - > zoomFactor ;
}
2017-03-11 17:33:59 +00:00
const QPinchGesture : : ChangeFlags changeFlags = pinch - > changeFlags ( ) ;
2016-10-15 13:22:35 +00:00
// Zoom
if ( pinch - > changeFlags ( ) & QPinchGesture : : ScaleFactorChanged ) {
d - > zoomFactor = vanillaZoom * pinch - > totalScaleFactor ( ) ;
d - > blockPixmapsRequest = true ;
updateZoom ( ZoomRefreshCurrent ) ;
d - > blockPixmapsRequest = false ;
2019-07-22 21:39:13 +00:00
viewport ( ) - > update ( ) ;
2016-10-15 13:22:35 +00:00
}
2017-03-11 17:33:59 +00:00
// Count the number of 90-degree rotations we did since the start of the pinch gesture.
// Otherwise a pinch turned to 90 degrees and held there will rotate the page again and again.
static int rotations = 0 ;
if ( changeFlags & QPinchGesture : : RotationAngleChanged ) {
// Rotation angle relative to the accumulated page rotations triggered by the current pinch
// We actually turn at 80 degrees rather than at 90 degrees. That's less strain on the hands.
const qreal relativeAngle = pinch - > rotationAngle ( ) - rotations * 90 ;
if ( relativeAngle > 80 ) {
slotRotateClockwise ( ) ;
rotations + + ;
}
if ( relativeAngle < - 80 ) {
slotRotateCounterClockwise ( ) ;
rotations - - ;
}
}
if ( pinch - > state ( ) = = Qt : : GestureFinished ) {
rotations = 0 ;
}
2016-10-15 13:22:35 +00:00
return true ;
}
return false ;
}
2009-06-29 20:55:50 +00:00
void PageView : : paintEvent ( QPaintEvent * pe )
2006-09-27 10:28:03 +00:00
{
2009-06-29 20:55:50 +00:00
const QPoint areaPos = contentAreaPosition ( ) ;
2006-10-07 14:40:32 +00:00
// create the rect into contents from the clipped screen rect
QRect viewportRect = viewport ( ) - > rect ( ) ;
2009-06-29 20:55:50 +00:00
viewportRect . translate ( areaPos ) ;
2016-07-24 21:46:53 +00:00
QRect contentsRect = pe - > rect ( ) . translated ( areaPos ) . intersected ( viewportRect ) ;
2006-10-07 14:40:32 +00:00
if ( ! contentsRect . isValid ( ) )
return ;
2006-09-27 10:28:03 +00:00
2006-10-22 13:49:11 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < " paintevent " < < contentsRect ;
2006-10-22 13:49:11 +00:00
# endif
2006-10-07 14:40:32 +00:00
// create the screen painter. a pixel painted at contentsX,contentsY
// appears to the top-left corner of the scrollview.
2009-06-29 20:55:50 +00:00
QPainter screenPainter ( viewport ( ) ) ;
// translate to simulate the scrolled content widget
screenPainter . translate ( - areaPos ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
// selectionRect is the normalized mouse selection rect
QRect selectionRect = d - > mouseSelectionRect ;
if ( ! selectionRect . isNull ( ) )
selectionRect = selectionRect . normalized ( ) ;
// selectionRectInternal without the border
QRect selectionRectInternal = selectionRect ;
selectionRectInternal . adjust ( 1 , 1 , - 1 , - 1 ) ;
// color for blending
QColor selBlendColor = ( selectionRect . width ( ) > 8 | | selectionRect . height ( ) > 8 ) ? d - > mouseSelectionColor : Qt : : red ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
// subdivide region into rects
2019-07-23 14:48:52 +00:00
QRegion rgn = pe - > region ( ) ;
2006-10-07 14:40:32 +00:00
// preprocess rects area to see if it worths or not using subdivision
uint summedArea = 0 ;
2019-07-23 14:48:52 +00:00
for ( const QRect & r : rgn ) {
2006-10-07 14:40:32 +00:00
summedArea + = r . width ( ) * r . height ( ) ;
2006-09-27 10:28:03 +00:00
}
2006-10-07 14:40:32 +00:00
// very elementary check: SUMj(Region[j].area) is less than boundingRect.area
2019-07-23 14:48:52 +00:00
const bool useSubdivision = summedArea < ( 0.6 * contentsRect . width ( ) * contentsRect . height ( ) ) ;
2006-10-07 14:40:32 +00:00
if ( ! useSubdivision ) {
2019-07-23 14:48:52 +00:00
rgn = contentsRect ;
2020-07-10 22:15:05 +00:00
}
2006-10-07 14:40:32 +00:00
// iterate over the rects (only one loop if not using subdivision)
2019-07-23 14:48:52 +00:00
for ( const QRect & r : rgn ) {
2006-10-07 14:40:32 +00:00
if ( useSubdivision ) {
// set 'contentsRect' to a part of the sub-divided region
2019-07-23 14:48:52 +00:00
contentsRect = r . translated ( areaPos ) . intersected ( viewportRect ) ;
2006-10-07 14:40:32 +00:00
if ( ! contentsRect . isValid ( ) )
continue ;
2019-07-23 14:48:52 +00:00
}
2006-10-22 13:49:11 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < contentsRect ;
2006-10-22 13:49:11 +00:00
# endif
2004-10-31 12:43:13 +00:00
2006-10-07 14:40:32 +00:00
// note: this check will take care of all things requiring alpha blending (not only selection)
bool wantCompositing = ! selectionRect . isNull ( ) & & contentsRect . intersects ( selectionRect ) ;
2011-10-12 13:50:56 +00:00
// also alpha-blend when there is a table selection...
wantCompositing | = ! d - > tableSelectionParts . isEmpty ( ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
if ( wantCompositing & & Okular : : Settings : : enableCompositing ( ) ) {
// create pixmap and open a painter over it (contents{left,top} becomes pixmap {0,0})
2017-10-14 12:47:20 +00:00
QPixmap doubleBuffer ( contentsRect . size ( ) * devicePixelRatioF ( ) ) ;
doubleBuffer . setDevicePixelRatio ( devicePixelRatioF ( ) ) ;
2006-10-07 14:40:32 +00:00
QPainter pixmapPainter ( & doubleBuffer ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
pixmapPainter . translate ( - contentsRect . left ( ) , - contentsRect . top ( ) ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
// 1) Layer 0: paint items and clear bg on unpainted rects
drawDocumentOnPainter ( contentsRect , & pixmapPainter ) ;
2011-10-12 13:50:56 +00:00
// 2a) Layer 1a: paint (blend) transparent selection (rectangle)
2006-10-07 14:40:32 +00:00
if ( ! selectionRect . isNull ( ) & & selectionRect . intersects ( contentsRect ) & & ! selectionRectInternal . contains ( contentsRect ) ) {
QRect blendRect = selectionRectInternal . intersected ( contentsRect ) ;
// skip rectangles covered by the selection's border
if ( blendRect . isValid ( ) ) {
// grab current pixmap into a new one to colorize contents
2017-10-14 12:47:20 +00:00
QPixmap blendedPixmap ( blendRect . width ( ) * devicePixelRatioF ( ) , blendRect . height ( ) * devicePixelRatioF ( ) ) ;
blendedPixmap . setDevicePixelRatio ( devicePixelRatioF ( ) ) ;
2006-10-07 14:40:32 +00:00
QPainter p ( & blendedPixmap ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
p . drawPixmap ( 0 ,
2020-07-10 22:15:05 +00:00
0 ,
2006-10-07 14:40:32 +00:00
doubleBuffer ,
2018-04-09 21:58:37 +00:00
( blendRect . left ( ) - contentsRect . left ( ) ) * devicePixelRatioF ( ) ,
( blendRect . top ( ) - contentsRect . top ( ) ) * devicePixelRatioF ( ) ,
2017-10-14 12:47:20 +00:00
blendRect . width ( ) * devicePixelRatioF ( ) ,
blendRect . height ( ) * devicePixelRatioF ( ) ) ;
2020-07-10 22:15:05 +00:00
2019-03-13 05:58:11 +00:00
QColor blCol = selBlendColor . darker ( 140 ) ;
2007-05-19 10:42:10 +00:00
blCol . setAlphaF ( 0.2 ) ;
p . fillRect ( blendedPixmap . rect ( ) , blCol ) ;
2020-07-10 22:15:05 +00:00
p . end ( ) ;
2006-10-07 14:40:32 +00:00
// copy the blended pixmap back to its place
pixmapPainter . drawPixmap ( blendRect . left ( ) , blendRect . top ( ) , blendedPixmap ) ;
2020-07-10 22:15:05 +00:00
}
2006-10-07 14:40:32 +00:00
// draw border (red if the selection is too small)
pixmapPainter . setPen ( selBlendColor ) ;
pixmapPainter . drawRect ( selectionRect . adjusted ( 0 , 0 , - 1 , - 1 ) ) ;
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
// 2b) Layer 1b: paint (blend) transparent selection (table)
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-12 13:50:56 +00:00
QRect selectionPartRect = tsp . rectInItem . geometry ( tsp . item - > uncroppedWidth ( ) , tsp . item - > uncroppedHeight ( ) ) ;
selectionPartRect . translate ( tsp . item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
QRect selectionPartRectInternal = selectionPartRect ;
selectionPartRectInternal . adjust ( 1 , 1 , - 1 , - 1 ) ;
2006-10-07 14:40:32 +00:00
if ( ! selectionPartRect . isNull ( ) & & selectionPartRect . intersects ( contentsRect ) & & ! selectionPartRectInternal . contains ( contentsRect ) ) {
2016-07-24 21:46:53 +00:00
QRect blendRect = selectionPartRectInternal . intersected ( contentsRect ) ;
2006-10-07 14:40:32 +00:00
// skip rectangles covered by the selection's border
if ( blendRect . isValid ( ) ) {
// grab current pixmap into a new one to colorize contents
2017-10-14 12:47:20 +00:00
QPixmap blendedPixmap ( blendRect . width ( ) * devicePixelRatioF ( ) , blendRect . height ( ) * devicePixelRatioF ( ) ) ;
blendedPixmap . setDevicePixelRatio ( devicePixelRatioF ( ) ) ;
2006-10-07 14:40:32 +00:00
QPainter p ( & blendedPixmap ) ;
p . drawPixmap ( 0 ,
0 ,
doubleBuffer ,
2018-04-09 21:58:37 +00:00
( blendRect . left ( ) - contentsRect . left ( ) ) * devicePixelRatioF ( ) ,
( blendRect . top ( ) - contentsRect . top ( ) ) * devicePixelRatioF ( ) ,
2017-10-14 12:47:20 +00:00
blendRect . width ( ) * devicePixelRatioF ( ) ,
blendRect . height ( ) * devicePixelRatioF ( ) ) ;
2020-07-10 22:15:05 +00:00
2019-03-13 05:58:11 +00:00
QColor blCol = d - > mouseSelectionColor . darker ( 140 ) ;
2007-05-19 10:42:10 +00:00
blCol . setAlphaF ( 0.2 ) ;
p . fillRect ( blendedPixmap . rect ( ) , blCol ) ;
2008-06-06 22:03:30 +00:00
p . end ( ) ;
2006-10-07 14:40:32 +00:00
// copy the blended pixmap back to its place
pixmapPainter . drawPixmap ( blendRect . left ( ) , blendRect . top ( ) , blendedPixmap ) ;
}
// draw border (red if the selection is too small)
2016-07-24 21:46:53 +00:00
pixmapPainter . setPen ( d - > mouseSelectionColor ) ;
2011-10-12 13:50:56 +00:00
pixmapPainter . drawRect ( selectionPartRect . adjusted ( 0 , 0 , - 1 , - 1 ) ) ;
2004-10-31 17:04:04 +00:00
}
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
drawTableDividers ( & pixmapPainter ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
// 3a) Layer 1: give annotator painting control
2006-10-07 14:40:32 +00:00
if ( d - > annotator & & d - > annotator - > routePaints ( contentsRect ) )
d - > annotator - > routePaint ( & pixmapPainter , contentsRect ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
// 3b) Layer 1: give mouseAnnotation painting control
d - > mouseAnnotation - > routePaint ( & pixmapPainter , contentsRect ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
// 4) Layer 2: overlays
if ( Okular : : Settings : : debugDrawBoundaries ( ) ) {
pixmapPainter . setPen ( Qt : : blue ) ;
pixmapPainter . drawRect ( contentsRect ) ;
2020-07-10 22:15:05 +00:00
}
2011-10-17 19:56:45 +00:00
2006-10-07 14:40:32 +00:00
// finish painting and draw contents
pixmapPainter . end ( ) ;
screenPainter . drawPixmap ( contentsRect . left ( ) , contentsRect . top ( ) , doubleBuffer ) ;
2020-07-10 22:15:05 +00:00
} else {
2006-10-07 14:40:32 +00:00
// 1) Layer 0: paint items and clear bg on unpainted rects
drawDocumentOnPainter ( contentsRect , & screenPainter ) ;
2011-10-12 13:50:56 +00:00
// 2a) Layer 1a: paint opaque selection (rectangle)
2006-10-07 14:40:32 +00:00
if ( ! selectionRect . isNull ( ) & & selectionRect . intersects ( contentsRect ) & & ! selectionRectInternal . contains ( contentsRect ) ) {
2019-03-13 05:58:11 +00:00
screenPainter . setPen ( palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) . darker ( 110 ) ) ;
2006-10-07 14:40:32 +00:00
screenPainter . drawRect ( selectionRect ) ;
2004-10-31 13:55:07 +00:00
}
2011-10-12 13:50:56 +00:00
// 2b) Layer 1b: paint opaque selection (table)
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-12 13:50:56 +00:00
QRect selectionPartRect = tsp . rectInItem . geometry ( tsp . item - > uncroppedWidth ( ) , tsp . item - > uncroppedHeight ( ) ) ;
selectionPartRect . translate ( tsp . item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
QRect selectionPartRectInternal = selectionPartRect ;
selectionPartRectInternal . adjust ( 1 , 1 , - 1 , - 1 ) ;
if ( ! selectionPartRect . isNull ( ) & & selectionPartRect . intersects ( contentsRect ) & & ! selectionPartRectInternal . contains ( contentsRect ) ) {
2019-03-13 05:58:11 +00:00
screenPainter . setPen ( palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) . darker ( 110 ) ) ;
2006-10-07 14:40:32 +00:00
screenPainter . drawRect ( selectionPartRect ) ;
}
2004-10-31 13:55:07 +00:00
}
2011-10-12 13:50:56 +00:00
drawTableDividers ( & screenPainter ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
// 3a) Layer 1: give annotator painting control
2006-10-07 14:40:32 +00:00
if ( d - > annotator & & d - > annotator - > routePaints ( contentsRect ) )
d - > annotator - > routePaint ( & screenPainter , contentsRect ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
// 3b) Layer 1: give mouseAnnotation painting control
d - > mouseAnnotation - > routePaint ( & screenPainter , contentsRect ) ;
2020-07-10 22:15:05 +00:00
2006-10-07 14:40:32 +00:00
// 4) Layer 2: overlays
if ( Okular : : Settings : : debugDrawBoundaries ( ) ) {
screenPainter . setPen ( Qt : : red ) ;
screenPainter . drawRect ( contentsRect ) ;
2020-07-10 22:15:05 +00:00
}
2004-10-31 12:43:13 +00:00
}
2020-07-10 22:15:05 +00:00
}
2004-10-29 21:52:06 +00:00
}
2011-10-12 13:50:56 +00:00
void PageView : : drawTableDividers ( QPainter * screenPainter )
{
if ( ! d - > tableSelectionParts . isEmpty ( ) ) {
2019-03-13 05:58:11 +00:00
screenPainter - > setPen ( d - > mouseSelectionColor . darker ( ) ) ;
2011-10-31 15:33:03 +00:00
if ( d - > tableDividersGuessed ) {
QPen p = screenPainter - > pen ( ) ;
p . setStyle ( Qt : : DashLine ) ;
screenPainter - > setPen ( p ) ;
}
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-12 13:50:56 +00:00
QRect selectionPartRect = tsp . rectInItem . geometry ( tsp . item - > uncroppedWidth ( ) , tsp . item - > uncroppedHeight ( ) ) ;
selectionPartRect . translate ( tsp . item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
QRect selectionPartRectInternal = selectionPartRect ;
selectionPartRectInternal . adjust ( 1 , 1 , - 1 , - 1 ) ;
2019-12-09 13:39:47 +00:00
for ( double col : qAsConst ( d - > tableSelectionCols ) ) {
2011-10-12 13:50:56 +00:00
if ( col > = tsp . rectInSelection . left & & col < = tsp . rectInSelection . right ) {
col = ( col - tsp . rectInSelection . left ) / ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
const int x = selectionPartRect . left ( ) + col * selectionPartRect . width ( ) + 0.5 ;
screenPainter - > drawLine ( x , selectionPartRectInternal . top ( ) , x , selectionPartRectInternal . top ( ) + selectionPartRectInternal . height ( ) ) ;
}
2020-07-10 22:15:05 +00:00
}
2019-12-09 13:39:47 +00:00
for ( double row : qAsConst ( d - > tableSelectionRows ) ) {
2011-10-12 13:50:56 +00:00
if ( row > = tsp . rectInSelection . top & & row < = tsp . rectInSelection . bottom ) {
row = ( row - tsp . rectInSelection . top ) / ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
const int y = selectionPartRect . top ( ) + row * selectionPartRect . height ( ) + 0.5 ;
screenPainter - > drawLine ( selectionPartRectInternal . left ( ) , y , selectionPartRectInternal . left ( ) + selectionPartRectInternal . width ( ) , y ) ;
}
}
}
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
}
2006-11-19 00:04:16 +00:00
void PageView : : resizeEvent ( QResizeEvent * e )
2004-10-29 21:52:06 +00:00
{
2005-02-26 18:05:01 +00:00
if ( d - > items . isEmpty ( ) ) {
2009-06-29 20:55:50 +00:00
resizeContentArea ( e - > size ( ) ) ;
2005-02-26 18:05:01 +00:00
return ;
2006-11-19 00:04:16 +00:00
}
2005-02-26 18:05:01 +00:00
2014-07-10 21:14:01 +00:00
if ( ( d - > zoomMode = = ZoomFitWidth | | d - > zoomMode = = ZoomFitAuto ) & & ! verticalScrollBar ( ) - > isVisible ( ) & & qAbs ( e - > oldSize ( ) . height ( ) - e - > size ( ) . height ( ) ) < verticalScrollBar ( ) - > width ( ) & & d - > verticalScrollBarVisible ) {
2008-12-08 16:09:15 +00:00
// this saves us from infinite resizing loop because of scrollbars appearing and disappearing
// see bug 160628 for more info
2010-09-11 13:34:22 +00:00
// TODO looks are still a bit ugly because things are left uncentered
2008-12-08 16:09:15 +00:00
// but better a bit ugly than unusable
2010-07-20 22:24:57 +00:00
d - > verticalScrollBarVisible = false ;
2009-06-29 20:55:50 +00:00
resizeContentArea ( e - > size ( ) ) ;
2008-12-08 16:09:15 +00:00
return ;
2014-07-10 21:14:01 +00:00
} else if ( d - > zoomMode = = ZoomFitAuto & & ! horizontalScrollBar ( ) - > isVisible ( ) & & qAbs ( e - > oldSize ( ) . width ( ) - e - > size ( ) . width ( ) ) < horizontalScrollBar ( ) - > height ( ) & & d - > horizontalScrollBarVisible ) {
2013-08-18 15:19:20 +00:00
// this saves us from infinite resizing loop because of scrollbars appearing and disappearing
// TODO looks are still a bit ugly because things are left uncentered
// but better a bit ugly than unusable
d - > horizontalScrollBarVisible = false ;
resizeContentArea ( e - > size ( ) ) ;
return ;
}
2008-12-08 16:09:15 +00:00
2005-03-24 19:10:41 +00:00
// start a timer that will refresh the pixmap after 0.2s
2011-03-17 15:24:44 +00:00
d - > delayResizeEventTimer - > start ( 200 ) ;
2010-07-20 22:24:57 +00:00
d - > verticalScrollBarVisible = verticalScrollBar ( ) - > isVisible ( ) ;
2013-08-18 15:19:20 +00:00
d - > horizontalScrollBarVisible = horizontalScrollBar ( ) - > isVisible ( ) ;
2004-10-29 21:52:06 +00:00
}
void PageView : : keyPressEvent ( QKeyEvent * e )
{
e - > accept ( ) ;
2005-01-18 16:43:36 +00:00
2005-02-01 18:24:16 +00:00
// if performing a selection or dyn zooming, disable keys handling
2020-08-31 15:17:58 +00:00
if ( ( d - > mouseSelecting & & e - > key ( ) ! = Qt : : Key_Escape ) | | ( QApplication : : mouseButtons ( ) & Qt : : MiddleButton ) )
2005-02-01 18:24:16 +00:00
return ;
2004-10-29 21:52:06 +00:00
// move/scroll page by using keys
switch ( e - > key ( ) ) {
2008-11-29 13:22:32 +00:00
case Qt : : Key_J :
2006-03-24 20:40:02 +00:00
case Qt : : Key_Down :
2019-11-15 16:08:25 +00:00
slotScrollDown ( 1 /* go down 1 step */ ) ;
2019-10-05 21:18:32 +00:00
break ;
2006-03-24 20:40:02 +00:00
case Qt : : Key_PageDown :
2019-10-05 21:18:32 +00:00
slotScrollDown ( ) ;
break ;
case Qt : : Key_K :
2007-07-20 12:18:55 +00:00
case Qt : : Key_Up :
2019-11-15 16:08:25 +00:00
slotScrollUp ( 1 /* go up 1 step */ ) ;
2019-10-05 21:18:32 +00:00
break ;
2007-07-20 12:18:55 +00:00
case Qt : : Key_PageUp :
case Qt : : Key_Backspace :
2019-10-05 21:18:32 +00:00
slotScrollUp ( ) ;
break ;
2006-03-24 20:40:02 +00:00
case Qt : : Key_Left :
2008-11-29 13:22:32 +00:00
case Qt : : Key_H :
2012-05-22 22:23:36 +00:00
if ( horizontalScrollBar ( ) - > maximum ( ) = = 0 ) {
// if we cannot scroll we go to the previous page vertically
int next_page = d - > document - > currentPage ( ) - viewColumns ( ) ;
d - > document - > setViewportPage ( next_page ) ;
2019-11-15 16:08:25 +00:00
} else {
2020-09-11 21:19:36 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( - horizontalScrollBar ( ) - > singleStep ( ) , 0 ) , d - > currentShortScrollDuration ) ;
2019-11-15 16:08:25 +00:00
}
2004-10-29 21:52:06 +00:00
break ;
2006-03-24 20:40:02 +00:00
case Qt : : Key_Right :
2008-11-29 13:22:32 +00:00
case Qt : : Key_L :
2012-05-22 22:23:36 +00:00
if ( horizontalScrollBar ( ) - > maximum ( ) = = 0 ) {
// if we cannot scroll we advance the page vertically
int next_page = d - > document - > currentPage ( ) + viewColumns ( ) ;
d - > document - > setViewportPage ( next_page ) ;
2019-11-15 16:08:25 +00:00
} else {
2020-09-11 21:19:36 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( horizontalScrollBar ( ) - > singleStep ( ) , 0 ) , d - > currentShortScrollDuration ) ;
2019-11-15 16:08:25 +00:00
}
2004-10-29 21:52:06 +00:00
break ;
2006-10-28 23:27:44 +00:00
case Qt : : Key_Escape :
2012-07-12 18:46:24 +00:00
emit escPressed ( ) ;
2011-10-31 15:33:03 +00:00
selectionClear ( d - > tableDividersGuessed ? ClearOnlyDividers : ClearAllSelection ) ;
2006-10-28 23:27:44 +00:00
d - > mousePressPos = QPoint ( ) ;
if ( d - > aPrevAction ) {
d - > aPrevAction - > trigger ( ) ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
2006-10-28 23:27:44 +00:00
}
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
d - > mouseAnnotation - > routeKeyPressEvent ( e ) ;
2006-10-28 23:27:44 +00:00
break ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
case Qt : : Key_Delete :
d - > mouseAnnotation - > routeKeyPressEvent ( e ) ;
2020-07-10 22:15:05 +00:00
break ;
2006-03-24 20:40:02 +00:00
case Qt : : Key_Shift :
case Qt : : Key_Control :
2005-02-01 18:24:16 +00:00
if ( d - > autoScrollTimer ) {
if ( d - > autoScrollTimer - > isActive ( ) )
d - > autoScrollTimer - > stop ( ) ;
2004-10-29 21:52:06 +00:00
else
2016-10-01 10:52:30 +00:00
slotAutoScroll ( ) ;
2004-10-29 21:52:06 +00:00
return ;
2020-07-10 22:15:05 +00:00
}
2017-07-28 09:13:29 +00:00
// fallthrough
2020-07-10 22:15:05 +00:00
default :
2004-10-29 21:52:06 +00:00
e - > ignore ( ) ;
2020-07-10 22:15:05 +00:00
return ;
2004-10-29 21:52:06 +00:00
}
// if a known key has been pressed, stop scrolling the page
2005-02-01 18:24:16 +00:00
if ( d - > autoScrollTimer ) {
2004-10-29 21:52:06 +00:00
d - > scrollIncrement = 0 ;
2005-02-01 18:24:16 +00:00
d - > autoScrollTimer - > stop ( ) ;
2004-10-29 21:52:06 +00:00
}
}
2007-09-23 17:45:36 +00:00
void PageView : : keyReleaseEvent ( QKeyEvent * e )
{
e - > accept ( ) ;
2013-06-23 18:42:19 +00:00
if ( d - > annotator & & d - > annotator - > active ( ) ) {
2007-09-23 17:45:36 +00:00
if ( d - > annotator - > routeKeyEvent ( e ) )
return ;
}
if ( e - > key ( ) = = Qt : : Key_Escape & & d - > autoScrollTimer ) {
d - > scrollIncrement = 0 ;
d - > autoScrollTimer - > stop ( ) ;
}
}
2006-08-14 15:03:12 +00:00
void PageView : : inputMethodEvent ( QInputMethodEvent * e )
{
2007-03-17 22:58:41 +00:00
Q_UNUSED ( e )
2006-08-14 15:03:12 +00:00
}
2012-10-15 18:11:47 +00:00
void PageView : : tabletEvent ( QTabletEvent * e )
{
// Ignore tablet events that we don't care about
if ( ! ( e - > type ( ) = = QEvent : : TabletPress | | e - > type ( ) = = QEvent : : TabletRelease | | e - > type ( ) = = QEvent : : TabletMove ) ) {
e - > ignore ( ) ;
return ;
}
// Determine pen state
bool penReleased = false ;
if ( e - > type ( ) = = QEvent : : TabletPress ) {
d - > penDown = true ;
}
if ( e - > type ( ) = = QEvent : : TabletRelease ) {
d - > penDown = false ;
penReleased = true ;
}
// If we're editing an annotation and the tablet pen is either down or just released
// then dispatch event to annotator
2013-06-23 18:42:19 +00:00
if ( d - > annotator & & d - > annotator - > active ( ) & & ( d - > penDown | | penReleased ) ) {
2020-07-17 15:52:10 +00:00
// accept the event, otherwise it comes back as a mouse event
e - > accept ( ) ;
2012-10-15 18:11:47 +00:00
const QPoint eventPos = contentAreaPoint ( e - > pos ( ) ) ;
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2012-10-15 18:21:43 +00:00
const QPoint localOriginInGlobal = mapToGlobal ( QPoint ( 0 , 0 ) ) ;
2012-10-15 18:11:47 +00:00
// routeTabletEvent will accept or ignore event as appropriate
d - > annotator - > routeTabletEvent ( e , pageItem , localOriginInGlobal ) ;
} else {
e - > ignore ( ) ;
}
}
2009-06-29 20:55:50 +00:00
void PageView : : mouseMoveEvent ( QMouseEvent * e )
2004-10-29 21:52:06 +00:00
{
2018-12-05 23:24:39 +00:00
// For some reason in Qt 5.11.2 (no idea when this started) all wheel
// events are followed by mouse move events (without changing position),
// so we only actually reset the controlWheelAccumulatedDelta if there is a mouse movement
if ( e - > globalPos ( ) ! = d - > previousMouseMovePos ) {
d - > controlWheelAccumulatedDelta = 0 ;
}
d - > previousMouseMovePos = e - > globalPos ( ) ;
2017-03-03 22:55:06 +00:00
2005-01-29 12:32:59 +00:00
// don't perform any mouse action when no document is shown
if ( d - > items . isEmpty ( ) )
return ;
2004-11-16 17:36:02 +00:00
// if holding mouse mid button, perform zoom
2020-08-31 15:17:58 +00:00
if ( e - > buttons ( ) & Qt : : MiddleButton ) {
2005-03-24 19:10:41 +00:00
int mouseY = e - > globalPos ( ) . y ( ) ;
int deltaY = d - > mouseMidLastY - mouseY ;
// wrap mouse from top to bottom
2014-09-28 12:14:19 +00:00
const QRect mouseContainer = QApplication : : desktop ( ) - > screenGeometry ( this ) ;
2010-08-14 11:59:49 +00:00
const int absDeltaY = abs ( deltaY ) ;
if ( absDeltaY > mouseContainer . height ( ) / 2 ) {
deltaY = mouseContainer . height ( ) - absDeltaY ;
}
2010-09-11 13:34:22 +00:00
2012-11-15 22:18:59 +00:00
const float upperZoomLimit = d - > document - > supportsTiles ( ) ? 15.99 : 3.99 ;
2005-03-24 19:10:41 +00:00
if ( mouseY < = mouseContainer . top ( ) + 4 & & d - > zoomFactor < upperZoomLimit ) {
mouseY = mouseContainer . bottom ( ) - 5 ;
QCursor : : setPos ( e - > globalPos ( ) . x ( ) , mouseY ) ;
}
// wrap mouse from bottom to top
else if ( mouseY > = mouseContainer . bottom ( ) - 4 & & d - > zoomFactor > 0.101 ) {
mouseY = mouseContainer . top ( ) + 5 ;
QCursor : : setPos ( e - > globalPos ( ) . x ( ) , mouseY ) ;
}
// remember last position
d - > mouseMidLastY = mouseY ;
// update zoom level, perform zoom and redraw
if ( deltaY ) {
d - > zoomFactor * = ( 1.0 + ( ( double ) deltaY / 500.0 ) ) ;
2014-12-11 23:48:41 +00:00
d - > blockPixmapsRequest = true ;
2005-03-24 19:10:41 +00:00
updateZoom ( ZoomRefreshCurrent ) ;
2014-12-11 23:48:41 +00:00
d - > blockPixmapsRequest = false ;
2019-07-22 21:39:13 +00:00
viewport ( ) - > update ( ) ;
2005-03-24 19:10:41 +00:00
}
2004-11-16 17:36:02 +00:00
return ;
}
2004-10-29 21:52:06 +00:00
2009-06-29 20:55:50 +00:00
const QPoint eventPos = contentAreaPoint ( e - > pos ( ) ) ;
2005-02-18 18:24:45 +00:00
// if we're editing an annotation, dispatch event to it
2013-06-23 18:42:19 +00:00
if ( d - > annotator & & d - > annotator - > active ( ) ) {
2009-06-29 20:55:50 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2013-07-02 21:29:20 +00:00
updateCursor ( eventPos ) ;
2012-10-15 18:11:47 +00:00
d - > annotator - > routeMouseEvent ( e , pageItem ) ;
2005-02-18 18:24:45 +00:00
return ;
}
2006-09-28 21:41:50 +00:00
bool leftButton = ( e - > buttons ( ) = = Qt : : LeftButton ) ;
2006-09-28 22:19:31 +00:00
bool rightButton = ( e - > buttons ( ) = = Qt : : RightButton ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
2014-12-10 14:33:27 +00:00
switch ( d - > mouseMode ) {
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : Browse : {
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2004-10-29 21:52:06 +00:00
if ( leftButton ) {
2010-03-25 20:59:16 +00:00
d - > leftClickTimer . stop ( ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
if ( pageItem & & d - > mouseAnnotation - > isActive ( ) ) {
// if left button pressed and annotation is focused, forward move event
d - > mouseAnnotation - > routeMouseMoveEvent ( pageItem , eventPos , leftButton ) ;
2020-07-10 22:15:05 +00:00
}
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
// drag page
2020-07-10 22:15:05 +00:00
else {
2019-11-15 16:08:25 +00:00
if ( d - > scroller - > state ( ) = = QScroller : : Inactive | | d - > scroller - > state ( ) = = QScroller : : Scrolling ) {
d - > mouseGrabOffset = QPoint ( 0 , 0 ) ;
d - > scroller - > handleInput ( QScroller : : InputPress , e - > pos ( ) , e - > timestamp ( ) - 1 ) ;
2007-07-17 20:58:38 +00:00
}
2010-03-25 20:59:16 +00:00
2005-03-24 19:10:41 +00:00
setCursor ( Qt : : ClosedHandCursor ) ;
2014-09-28 12:14:19 +00:00
QPoint mousePos = e - > globalPos ( ) ;
2019-11-15 16:08:25 +00:00
const QRect mouseContainer = QApplication : : desktop ( ) - > screenGeometry ( this ) ;
2005-03-24 19:10:41 +00:00
// wrap mouse from top to bottom
Make selection scrolling go at 60 fps
Summary:
When you select a square with the right mouse button, and you go past the margin of the window (but where there is still space to go), okular scrolls the document so you can select more.
With this patch this automatic scrolling goes at 60 fps instead of 10, I made it so that the speed of the scroll is the same
Reviewers: #okular, aacid, sander, ngraham
Reviewed By: sander, ngraham
Subscribers: sander, ngraham, aacid, ahmedbilal, okular-devel, kezik
Tags: #okular
Differential Revision: https://phabricator.kde.org/D20437
2019-05-21 21:03:24 +00:00
if ( mousePos . y ( ) < = mouseContainer . top ( ) + 4 & & verticalScrollBar ( ) - > value ( ) < verticalScrollBar ( ) - > maximum ( ) - 10 ) {
2005-03-24 19:10:41 +00:00
mousePos . setY ( mouseContainer . bottom ( ) - 5 ) ;
QCursor : : setPos ( mousePos ) ;
2019-11-15 16:08:25 +00:00
d - > mouseGrabOffset - = QPoint ( 0 , mouseContainer . height ( ) ) ;
2004-10-29 21:52:06 +00:00
}
2010-08-30 18:24:11 +00:00
// wrap mouse from bottom to top
else if ( mousePos . y ( ) > = mouseContainer . bottom ( ) - 4 & & verticalScrollBar ( ) - > value ( ) > 10 ) {
2006-09-28 22:19:31 +00:00
mousePos . setY ( mouseContainer . top ( ) + 5 ) ;
2019-03-13 05:58:11 +00:00
d - > mouseGrabOffset + = QPoint ( 0 , mouseContainer . height ( ) ) ;
2020-07-10 22:15:05 +00:00
2012-09-28 15:57:03 +00:00
QCursor : : setPos ( mousePos ) ;
2006-09-28 22:19:31 +00:00
}
2020-07-10 22:15:05 +00:00
2019-11-15 16:08:25 +00:00
d - > scroller - > handleInput ( QScroller : : InputMove , e - > pos ( ) + d - > mouseGrabOffset , e - > timestamp ( ) ) ;
2006-09-28 22:19:31 +00:00
}
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
} else if ( rightButton & & ! d - > mousePressPos . isNull ( ) & & d - > aMouseSelect ) {
// if mouse moves 5 px away from the press point, switch to 'selection'
int deltaX = d - > mousePressPos . x ( ) - e - > globalPos ( ) . x ( ) , deltaY = d - > mousePressPos . y ( ) - e - > globalPos ( ) . y ( ) ;
2006-09-28 22:19:31 +00:00
if ( deltaX > 5 | | deltaX < - 5 | | deltaY > 5 | | deltaY < - 5 ) {
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
d - > aPrevAction = d - > aMouseNormal ;
d - > aMouseSelect - > trigger ( ) ;
QPoint newPos = eventPos + QPoint ( deltaX , deltaY ) ;
selectionStart ( newPos , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) . lighter ( 120 ) , false ) ;
2013-06-23 18:42:19 +00:00
updateSelection ( eventPos ) ;
2020-07-10 22:15:05 +00:00
break ;
2004-10-31 17:12:52 +00:00
}
2020-07-10 22:15:05 +00:00
} else {
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
/* Forward move events which are still not yet consumed by "mouse grab" or aMouseSelect */
d - > mouseAnnotation - > routeMouseMoveEvent ( pageItem , eventPos , leftButton ) ;
2017-09-21 20:16:31 +00:00
updateCursor ( ) ;
2020-07-10 22:15:05 +00:00
}
} break ;
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : Zoom :
case Okular : : Settings : : EnumMouseMode : : RectSelect :
case Okular : : Settings : : EnumMouseMode : : TableSelect :
2015-08-27 20:09:02 +00:00
case Okular : : Settings : : EnumMouseMode : : TrimSelect :
2005-01-28 17:21:28 +00:00
// set second corner of selection
2011-10-12 13:50:56 +00:00
if ( d - > mouseSelecting ) {
2012-09-28 15:57:03 +00:00
updateSelection ( eventPos ) ;
2017-09-21 20:16:31 +00:00
d - > mouseOverLinkObject = nullptr ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
}
2017-09-21 20:16:31 +00:00
updateCursor ( ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
break ;
2004-10-29 21:52:06 +00:00
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : Magnifier :
2014-02-24 22:42:10 +00:00
if ( e - > buttons ( ) ) // if any button is pressed at all
{
moveMagnifier ( e - > pos ( ) ) ;
updateMagnifier ( eventPos ) ;
}
break ;
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : TextSelect :
2019-01-11 07:09:34 +00:00
// if mouse moves 5 px away from the press point and the document supports text extraction, do 'textselection'
2009-06-29 20:55:50 +00:00
if ( ! d - > mouseTextSelecting & & ! d - > mousePressPos . isNull ( ) & & d - > document - > supportsSearching ( ) & & ( ( eventPos - d - > mouseSelectPos ) . manhattanLength ( ) > 5 ) ) {
2006-09-26 22:22:01 +00:00
d - > mouseTextSelecting = true ;
}
2012-09-28 15:57:03 +00:00
updateSelection ( eventPos ) ;
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2004-10-29 21:52:06 +00:00
break ;
}
}
2009-06-29 20:55:50 +00:00
void PageView : : mousePressEvent ( QMouseEvent * e )
2004-09-26 23:39:39 +00:00
{
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta = 0 ;
2005-01-29 12:32:59 +00:00
// don't perform any mouse action when no document is shown
if ( d - > items . isEmpty ( ) )
return ;
// if performing a selection or dyn zooming, disable mouse press
2020-08-31 15:17:58 +00:00
if ( d - > mouseSelecting | | ( e - > button ( ) ! = Qt : : MiddleButton & & ( e - > buttons ( ) & Qt : : MiddleButton ) ) )
2005-01-29 12:32:59 +00:00
return ;
2005-02-01 18:24:16 +00:00
// if the page is scrolling, stop it
if ( d - > autoScrollTimer ) {
d - > scrollIncrement = 0 ;
d - > autoScrollTimer - > stop ( ) ;
}
2005-03-24 19:10:41 +00:00
// if pressing mid mouse button while not doing other things, begin 'continuous zoom' mode
2020-08-31 15:17:58 +00:00
if ( e - > button ( ) = = Qt : : MiddleButton ) {
2005-03-24 19:10:41 +00:00
d - > mouseMidLastY = e - > globalPos ( ) . y ( ) ;
2006-06-03 13:01:15 +00:00
setCursor ( Qt : : SizeVerCursor ) ;
2004-11-16 17:36:02 +00:00
return ;
}
2004-10-20 16:41:13 +00:00
2009-06-29 20:55:50 +00:00
const QPoint eventPos = contentAreaPoint ( e - > pos ( ) ) ;
2005-02-18 18:24:45 +00:00
// if we're editing an annotation, dispatch event to it
2013-06-23 18:42:19 +00:00
if ( d - > annotator & & d - > annotator - > active ( ) ) {
2019-11-15 16:08:25 +00:00
d - > scroller - > stop ( ) ;
2009-06-29 20:55:50 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2012-10-15 18:11:47 +00:00
d - > annotator - > routeMouseEvent ( e , pageItem ) ;
2005-02-18 18:24:45 +00:00
return ;
}
2012-07-10 16:45:23 +00:00
// trigger history navigation for additional mouse buttons
if ( e - > button ( ) = = Qt : : XButton1 ) {
emit mouseBackButtonClick ( ) ;
return ;
}
if ( e - > button ( ) = = Qt : : XButton2 ) {
emit mouseForwardButtonClick ( ) ;
return ;
}
2005-01-29 12:32:59 +00:00
// update press / 'start drag' mouse position
d - > mousePressPos = e - > globalPos ( ) ;
2018-11-14 19:12:15 +00:00
// handle mode dependent mouse press actions
2006-09-26 22:22:01 +00:00
bool leftButton = e - > button ( ) = = Qt : : LeftButton , rightButton = e - > button ( ) = = Qt : : RightButton ;
2008-11-21 10:50:16 +00:00
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
// Not sure we should erase the selection when clicking with left.
2014-12-10 14:33:27 +00:00
if ( d - > mouseMode ! = Okular : : Settings : : EnumMouseMode : : TextSelect )
2006-06-10 17:06:03 +00:00
textSelectionClear ( ) ;
2008-11-21 10:50:16 +00:00
2014-12-10 14:33:27 +00:00
switch ( d - > mouseMode ) {
case Okular : : Settings : : EnumMouseMode : : Browse : // drag start / click / link following
2004-09-26 23:39:39 +00:00
{
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2004-10-20 16:41:13 +00:00
if ( leftButton ) {
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
if ( pageItem ) {
d - > mouseAnnotation - > routeMousePressEvent ( pageItem , eventPos ) ;
2004-09-30 18:16:12 +00:00
}
2012-06-29 10:39:42 +00:00
if ( ! d - > mouseOnRect ) {
2019-11-15 16:08:25 +00:00
d - > mouseGrabOffset = QPoint ( 0 , 0 ) ;
d - > scroller - > handleInput ( QScroller : : InputPress , e - > pos ( ) , e - > timestamp ( ) ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
d - > leftClickTimer . start ( QApplication : : doubleClickInterval ( ) + 10 ) ;
2020-07-10 22:15:05 +00:00
}
}
} break ;
2012-06-29 10:39:42 +00:00
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : Zoom : // set first corner of the zoom rect
2005-03-24 19:10:41 +00:00
if ( leftButton )
2009-06-29 20:55:50 +00:00
selectionStart ( eventPos , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) , false ) ;
2006-09-26 22:22:01 +00:00
else if ( rightButton )
2005-01-29 12:32:59 +00:00
updateZoom ( ZoomOut ) ;
2020-07-10 22:15:05 +00:00
break ;
2006-12-30 12:40:54 +00:00
2015-10-29 12:37:11 +00:00
case Okular : : Settings : : EnumMouseMode : : Magnifier :
moveMagnifier ( e - > pos ( ) ) ;
d - > magnifierView - > show ( ) ;
updateMagnifier ( eventPos ) ;
2020-07-10 22:15:05 +00:00
break ;
2006-12-30 12:40:54 +00:00
2017-03-08 23:37:03 +00:00
case Okular : : Settings : : EnumMouseMode : : RectSelect : // set first corner of the selection rect
case Okular : : Settings : : EnumMouseMode : : TrimSelect :
2017-09-21 20:16:31 +00:00
if ( leftButton ) {
2017-03-08 23:37:03 +00:00
selectionStart ( eventPos , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) . lighter ( 120 ) , false ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
}
break ;
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : TableSelect :
2017-09-21 20:16:31 +00:00
if ( leftButton ) {
2011-10-12 13:50:56 +00:00
if ( d - > tableSelectionParts . isEmpty ( ) ) {
2019-03-13 05:58:11 +00:00
selectionStart ( eventPos , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) . lighter ( 120 ) , false ) ;
2020-07-10 22:15:05 +00:00
} else {
2011-10-12 13:50:56 +00:00
QRect updatedRect ;
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-12 13:50:56 +00:00
QRect selectionPartRect = tsp . rectInItem . geometry ( tsp . item - > uncroppedWidth ( ) , tsp . item - > uncroppedHeight ( ) ) ;
selectionPartRect . translate ( tsp . item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
2004-09-26 23:39:39 +00:00
2012-03-09 17:43:40 +00:00
// This will update the whole table rather than just the added/removed divider
2009-06-29 20:55:50 +00:00
// (which can span more than one part).
updatedRect = updatedRect . united ( selectionPartRect ) ;
2005-01-29 12:32:59 +00:00
2014-02-24 22:42:10 +00:00
if ( ! selectionPartRect . contains ( eventPos ) )
continue ;
2012-03-09 17:43:40 +00:00
// At this point it's clear we're either adding or removing a divider manually, so obviously the user is happy with the guess (if any).
2019-03-13 05:58:11 +00:00
d - > tableDividersGuessed = false ;
2020-07-10 22:15:05 +00:00
2019-03-13 05:58:11 +00:00
// There's probably a neat trick to finding which edge it's closest to,
// but this way has the advantage of simplicity.
const int fromLeft = abs ( selectionPartRect . left ( ) - eventPos . x ( ) ) ;
2011-10-12 13:50:56 +00:00
const int fromRight = abs ( selectionPartRect . left ( ) + selectionPartRect . width ( ) - eventPos . x ( ) ) ;
const int fromTop = abs ( selectionPartRect . top ( ) - eventPos . y ( ) ) ;
const int fromBottom = abs ( selectionPartRect . top ( ) + selectionPartRect . height ( ) - eventPos . y ( ) ) ;
const int colScore = fromTop < fromBottom ? fromTop : fromBottom ;
const int rowScore = fromLeft < fromRight ? fromLeft : fromRight ;
2020-07-10 22:15:05 +00:00
2011-10-12 13:50:56 +00:00
if ( colScore < rowScore ) {
bool deleted = false ;
for ( int i = 0 ; i < d - > tableSelectionCols . length ( ) ; i + + ) {
const double col = ( d - > tableSelectionCols [ i ] - tsp . rectInSelection . left ) / ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
const int colX = selectionPartRect . left ( ) + col * selectionPartRect . width ( ) + 0.5 ;
if ( abs ( colX - eventPos . x ( ) ) < = 3 ) {
d - > tableSelectionCols . removeAt ( i ) ;
deleted = true ;
2020-07-10 22:15:05 +00:00
2011-10-12 13:50:56 +00:00
break ;
}
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
if ( ! deleted ) {
double col = eventPos . x ( ) - selectionPartRect . left ( ) ;
col / = selectionPartRect . width ( ) ; // at this point, it's normalised within the part
col * = ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
col + = tsp . rectInSelection . left ; // at this point, it's normalised within the whole table
2020-07-10 22:15:05 +00:00
2011-10-12 13:50:56 +00:00
d - > tableSelectionCols . append ( col ) ;
2019-03-12 12:13:53 +00:00
std : : sort ( d - > tableSelectionCols . begin ( ) , d - > tableSelectionCols . end ( ) ) ;
2020-07-10 22:15:05 +00:00
}
} else {
2012-10-15 18:11:47 +00:00
bool deleted = false ;
2019-03-12 12:13:53 +00:00
for ( int i = 0 ; i < d - > tableSelectionRows . length ( ) ; i + + ) {
const double row = ( d - > tableSelectionRows [ i ] - tsp . rectInSelection . top ) / ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
2011-10-12 13:50:56 +00:00
const int rowY = selectionPartRect . top ( ) + row * selectionPartRect . height ( ) + 0.5 ;
if ( abs ( rowY - eventPos . y ( ) ) < = 3 ) {
d - > tableSelectionRows . removeAt ( i ) ;
2011-10-31 15:33:03 +00:00
deleted = true ;
2020-07-10 22:15:05 +00:00
break ;
2011-10-12 13:50:56 +00:00
}
}
if ( ! deleted ) {
double row = eventPos . y ( ) - selectionPartRect . top ( ) ;
row / = selectionPartRect . height ( ) ; // at this point, it's normalised within the part
row * = ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
row + = tsp . rectInSelection . top ; // at this point, it's normalised within the whole table
2020-07-10 22:15:05 +00:00
2011-10-31 15:33:03 +00:00
d - > tableSelectionRows . append ( row ) ;
2019-03-12 12:13:53 +00:00
std : : sort ( d - > tableSelectionRows . begin ( ) , d - > tableSelectionRows . end ( ) ) ;
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
}
}
2006-09-26 22:22:01 +00:00
updatedRect . translate ( - contentAreaPosition ( ) ) ;
2011-10-12 13:50:56 +00:00
viewport ( ) - > update ( updatedRect ) ;
2006-09-26 22:22:01 +00:00
}
2020-07-10 22:15:05 +00:00
}
2006-09-26 22:22:01 +00:00
break ;
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : TextSelect :
2009-06-29 20:55:50 +00:00
d - > mouseSelectPos = eventPos ;
2005-03-24 19:10:41 +00:00
if ( ! rightButton ) {
2006-09-26 22:22:01 +00:00
textSelectionClear ( ) ;
2020-07-10 22:15:05 +00:00
}
break ;
2004-09-26 23:39:39 +00:00
}
}
2009-06-29 20:55:50 +00:00
void PageView : : mouseReleaseEvent ( QMouseEvent * e )
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
{
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta = 0 ;
2006-11-22 21:32:21 +00:00
// stop the drag scrolling
d - > dragScrollTimer . stop ( ) ;
2010-03-25 20:59:16 +00:00
d - > leftClickTimer . stop ( ) ;
2015-03-13 22:30:50 +00:00
const bool leftButton = e - > button ( ) = = Qt : : LeftButton ;
const bool rightButton = e - > button ( ) = = Qt : : RightButton ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
if ( d - > mouseAnnotation - > isActive ( ) & & leftButton ) {
2015-03-13 22:26:08 +00:00
// Just finished to move the annotation
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
d - > mouseAnnotation - > routeMouseReleaseEvent ( ) ;
2015-03-13 22:26:08 +00:00
}
2005-02-26 18:05:01 +00:00
// don't perform any mouse action when no document is shown..
2005-01-29 12:32:59 +00:00
if ( d - > items . isEmpty ( ) ) {
2005-02-26 18:05:01 +00:00
// ..except for right Clicks (emitted even it viewport is empty)
2006-03-24 20:40:02 +00:00
if ( e - > button ( ) = = Qt : : RightButton )
2017-09-05 21:27:18 +00:00
emit rightClick ( nullptr , e - > globalPos ( ) ) ;
2005-01-29 12:32:59 +00:00
return ;
2005-02-26 18:05:01 +00:00
}
2005-01-29 12:32:59 +00:00
2009-06-29 20:55:50 +00:00
const QPoint eventPos = contentAreaPoint ( e - > pos ( ) ) ;
2018-11-14 19:12:15 +00:00
// handle mode independent mid bottom zoom
2020-08-31 15:17:58 +00:00
if ( e - > button ( ) = = Qt : : MiddleButton ) {
2005-03-24 19:10:41 +00:00
// request pixmaps since it was disabled during drag
slotRequestVisiblePixmaps ( ) ;
// the cursor may now be over a link.. update it
2009-06-29 20:55:50 +00:00
updateCursor ( eventPos ) ;
2004-11-16 17:36:02 +00:00
return ;
}
2005-02-18 18:24:45 +00:00
// if we're editing an annotation, dispatch event to it
2013-06-23 18:42:19 +00:00
if ( d - > annotator & & d - > annotator - > active ( ) ) {
2009-06-29 20:55:50 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2012-10-15 18:11:47 +00:00
d - > annotator - > routeMouseEvent ( e , pageItem ) ;
2005-02-18 18:24:45 +00:00
return ;
}
2014-12-10 14:33:27 +00:00
switch ( d - > mouseMode ) {
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : Browse : {
2019-11-26 21:36:53 +00:00
d - > scroller - > handleInput ( QScroller : : InputRelease , e - > pos ( ) + d - > mouseGrabOffset , e - > timestamp ( ) ) ;
2020-07-10 22:15:05 +00:00
2005-01-02 11:50:38 +00:00
// return the cursor to its normal state after dragging
2011-08-11 21:46:09 +00:00
if ( cursor ( ) . shape ( ) = = Qt : : ClosedHandCursor )
2009-06-29 20:55:50 +00:00
updateCursor ( eventPos ) ;
2020-07-10 22:15:05 +00:00
2009-06-29 20:55:50 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2011-01-23 01:32:16 +00:00
const QPoint pressPos = contentAreaPoint ( mapFromGlobal ( d - > mousePressPos ) ) ;
const PageViewItem * pageItemPressPos = pickItemOnPoint ( pressPos . x ( ) , pressPos . y ( ) ) ;
2020-07-10 22:15:05 +00:00
2005-01-29 12:32:59 +00:00
// if the mouse has not moved since the press, that's a -click-
2011-01-23 01:32:16 +00:00
if ( leftButton & & pageItem & & pageItem = = pageItemPressPos & & ( ( d - > mousePressPos - e - > globalPos ( ) ) . manhattanLength ( ) < QApplication : : startDragDistance ( ) ) ) {
2017-09-21 20:16:31 +00:00
if ( ! mouseReleaseOverLink ( d - > mouseOverLinkObject ) & & ( e - > modifiers ( ) = = Qt : : ShiftModifier ) ) {
const double nX = pageItem - > absToPageX ( eventPos . x ( ) ) ;
const double nY = pageItem - > absToPageY ( eventPos . y ( ) ) ;
const Okular : : ObjectRect * rect ;
2006-11-17 22:15:15 +00:00
// TODO: find a better way to activate the source reference "links"
// for the moment they are activated with Shift + left click
2009-03-23 12:10:11 +00:00
// Search the nearest source reference.
rect = pageItem - > page ( ) - > objectRect ( Okular : : ObjectRect : : SourceRef , nX , nY , pageItem - > uncroppedWidth ( ) , pageItem - > uncroppedHeight ( ) ) ;
if ( ! rect ) {
2009-04-19 22:34:29 +00:00
static const double s_minDistance = 0.025 ; // FIXME?: empirical value?
2009-03-23 12:10:11 +00:00
double distance = 0.0 ;
rect = pageItem - > page ( ) - > nearestObjectRect ( Okular : : ObjectRect : : SourceRef , nX , nY , pageItem - > uncroppedWidth ( ) , pageItem - > uncroppedHeight ( ) , & distance ) ;
2014-09-21 21:54:20 +00:00
// distance is distanceSqr, adapt it to a normalized value
distance = distance / ( pow ( pageItem - > uncroppedWidth ( ) , 2 ) + pow ( pageItem - > uncroppedHeight ( ) , 2 ) ) ;
2009-03-23 12:10:11 +00:00
if ( rect & & ( distance > s_minDistance ) )
2017-09-05 21:27:18 +00:00
rect = nullptr ;
2009-03-23 12:10:11 +00:00
}
2006-11-17 22:15:15 +00:00
if ( rect ) {
2007-01-02 17:05:49 +00:00
const Okular : : SourceReference * ref = static_cast < const Okular : : SourceReference * > ( rect - > object ( ) ) ;
2006-11-17 22:15:15 +00:00
d - > document - > processSourceReference ( ref ) ;
2009-07-27 14:15:33 +00:00
} else {
const Okular : : SourceReference * ref = d - > document - > dynamicSourceReference ( pageItem - > pageNumber ( ) , nX * pageItem - > page ( ) - > width ( ) , nY * pageItem - > page ( ) - > height ( ) ) ;
if ( ref ) {
d - > document - > processSourceReference ( ref ) ;
delete ref ;
}
2009-03-23 12:10:11 +00:00
}
2020-07-10 22:15:05 +00:00
}
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
} else if ( rightButton & & ! d - > mouseAnnotation - > isModified ( ) ) {
2011-01-23 01:32:16 +00:00
if ( pageItem & & pageItem = = pageItemPressPos & & ( ( d - > mousePressPos - e - > globalPos ( ) ) . manhattanLength ( ) < QApplication : : startDragDistance ( ) ) ) {
2017-09-21 20:16:31 +00:00
QMenu * menu = createProcessLinkMenu ( pageItem , eventPos ) ;
2020-09-20 23:15:15 +00:00
const QRect & itemRect = pageItem - > uncroppedGeometry ( ) ;
const double nX = pageItem - > absToPageX ( eventPos . x ( ) ) ;
const double nY = pageItem - > absToPageY ( eventPos . y ( ) ) ;
const QLinkedList < const Okular : : ObjectRect * > annotRects = pageItem - > page ( ) - > objectRects ( Okular : : ObjectRect : : OAnnotation , nX , nY , itemRect . width ( ) , itemRect . height ( ) ) ;
AnnotationPopup annotPopup ( d - > document , AnnotationPopup : : MultiAnnotationMode , this ) ;
// Do not move annotPopup inside the if, it needs to live until menu->exec()
if ( ! annotRects . isEmpty ( ) ) {
for ( const Okular : : ObjectRect * annotRect : annotRects ) {
Okular : : Annotation * ann = ( ( Okular : : AnnotationObjectRect * ) annotRect ) - > annotation ( ) ;
if ( ann & & ( ann - > subType ( ) ! = Okular : : Annotation : : AWidget ) ) {
annotPopup . addAnnotation ( ann , pageItem - > pageNumber ( ) ) ;
}
}
connect ( & annotPopup , & AnnotationPopup : : openAnnotationWindow , this , & PageView : : openAnnotationWindow ) ;
if ( ! menu ) {
menu = new QMenu ( this ) ;
}
annotPopup . addActionsToMenu ( menu ) ;
}
2017-09-21 20:16:31 +00:00
if ( menu ) {
menu - > exec ( e - > globalPos ( ) ) ;
menu - > deleteLater ( ) ;
2006-09-26 22:22:01 +00:00
} else {
// a link can move us to another page or even to another document, there's no point in trying to
// process the click on the image once we have processes the click on the link
2020-09-20 23:15:15 +00:00
const Okular : : ObjectRect * rect = pageItem - > page ( ) - > objectRect ( Okular : : ObjectRect : : Image , nX , nY , itemRect . width ( ) , itemRect . height ( ) ) ;
2006-09-26 22:22:01 +00:00
if ( rect ) {
// handle right click over a image
} else {
// right click (if not within 5 px of the press point, the mode
// had been already changed to 'Selection' instead of 'Normal')
emit rightClick ( pageItem - > page ( ) , e - > globalPos ( ) ) ;
}
}
} else {
2005-01-29 12:32:59 +00:00
// right click (if not within 5 px of the press point, the mode
2004-11-05 01:11:50 +00:00
// had been already changed to 'Selection' instead of 'Normal')
2020-05-15 17:44:04 +00:00
emit rightClick ( pageItem ? pageItem - > page ( ) : nullptr , e - > globalPos ( ) ) ;
2004-11-03 17:35:48 +00:00
}
2020-07-10 22:15:05 +00:00
}
2014-02-24 22:42:10 +00:00
} break ;
2015-08-27 20:09:02 +00:00
case Okular : : Settings : : EnumMouseMode : : Zoom :
2017-09-21 20:16:31 +00:00
// if a selection rect has been defined, zoom into it
if ( leftButton & & d - > mouseSelecting ) {
QRect selRect = d - > mouseSelectionRect . normalized ( ) ;
if ( selRect . width ( ) < = 8 & & selRect . height ( ) < = 8 ) {
selectionClear ( ) ;
break ;
}
2015-08-27 20:09:02 +00:00
// find out new zoom ratio and normalized view center (relative to the contentsRect)
double zoom = qMin ( ( double ) viewport ( ) - > width ( ) / ( double ) selRect . width ( ) , ( double ) viewport ( ) - > height ( ) / ( double ) selRect . height ( ) ) ;
double nX = ( double ) ( selRect . left ( ) + selRect . right ( ) ) / ( 2.0 * ( double ) contentAreaWidth ( ) ) ;
double nY = ( double ) ( selRect . top ( ) + selRect . bottom ( ) ) / ( 2.0 * ( double ) contentAreaHeight ( ) ) ;
2020-07-10 22:15:05 +00:00
2015-08-27 20:09:02 +00:00
const float upperZoomLimit = d - > document - > supportsTiles ( ) ? 100.0 : 4.0 ;
if ( d - > zoomFactor < = upperZoomLimit | | zoom < = 1.0 ) {
2004-11-03 17:35:48 +00:00
d - > zoomFactor * = zoom ;
2004-11-05 01:11:50 +00:00
viewport ( ) - > setUpdatesEnabled ( false ) ;
2015-08-27 20:09:02 +00:00
updateZoom ( ZoomRefreshCurrent ) ;
2004-11-05 01:11:50 +00:00
viewport ( ) - > setUpdatesEnabled ( true ) ;
2015-08-27 20:09:02 +00:00
}
// recenter view and update the viewport
center ( ( int ) ( nX * contentAreaWidth ( ) ) , ( int ) ( nY * contentAreaHeight ( ) ) ) ;
viewport ( ) - > update ( ) ;
// hide message box and delete overlay window
selectionClear ( ) ;
2020-07-10 22:15:05 +00:00
}
2015-08-27 20:09:02 +00:00
break ;
2014-02-24 22:42:10 +00:00
case Okular : : Settings : : EnumMouseMode : : Magnifier :
2015-08-27 20:09:02 +00:00
d - > magnifierView - > hide ( ) ;
2020-07-10 22:15:05 +00:00
break ;
2015-08-27 20:09:02 +00:00
case Okular : : Settings : : EnumMouseMode : : TrimSelect : {
// if it is a left release checks if is over a previous link press
if ( leftButton & & mouseReleaseOverLink ( d - > mouseOverLinkObject ) ) {
selectionClear ( ) ;
2020-07-10 22:15:05 +00:00
break ;
}
2015-08-27 20:09:02 +00:00
// if mouse is released and selection is null this is a rightClick
if ( rightButton & & ! d - > mouseSelecting ) {
break ;
2020-07-10 22:15:05 +00:00
}
2015-08-27 20:09:02 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
// ensure end point rests within a page, or ignore
if ( ! pageItem ) {
break ;
}
QRect selectionRect = d - > mouseSelectionRect . normalized ( ) ;
2020-07-10 22:15:05 +00:00
2015-08-27 20:09:02 +00:00
double nLeft = pageItem - > absToPageX ( selectionRect . left ( ) ) ;
double nRight = pageItem - > absToPageX ( selectionRect . right ( ) ) ;
double nTop = pageItem - > absToPageY ( selectionRect . top ( ) ) ;
double nBottom = pageItem - > absToPageY ( selectionRect . bottom ( ) ) ;
if ( nLeft < 0 )
nLeft = 0 ;
if ( nTop < 0 )
nTop = 0 ;
if ( nRight > 1 )
nRight = 1 ;
if ( nBottom > 1 )
nBottom = 1 ;
d - > trimBoundingBox = Okular : : NormalizedRect ( nLeft , nTop , nRight , nBottom ) ;
2020-07-10 22:15:05 +00:00
2015-08-27 20:09:02 +00:00
// Trim Selection successfully done, hide prompt
2011-10-18 20:36:42 +00:00
d - > messageWindow - > hide ( ) ;
2015-08-27 20:09:02 +00:00
// clear widget selection and invalidate rect
selectionClear ( ) ;
// When Trim selection bbox interaction is over, we should switch to another mousemode.
2005-03-24 19:10:41 +00:00
if ( d - > aPrevAction ) {
2006-03-24 20:40:02 +00:00
d - > aPrevAction - > trigger ( ) ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
2020-07-10 22:15:05 +00:00
} else {
2015-08-27 20:09:02 +00:00
d - > aMouseNormal - > trigger ( ) ;
2020-07-10 22:15:05 +00:00
}
2015-08-27 20:09:02 +00:00
// with d->trimBoundingBox defined, redraw for trim to take visual effect
if ( d - > document - > pages ( ) > 0 ) {
slotRelayoutPages ( ) ;
2008-05-19 00:37:14 +00:00
slotRequestVisiblePixmaps ( ) ; // TODO: slotRelayoutPages() may have done this already!
2020-07-10 22:15:05 +00:00
}
break ;
}
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : RectSelect : {
2017-09-21 20:16:31 +00:00
// if it is a left release checks if is over a previous link press
if ( leftButton & & mouseReleaseOverLink ( d - > mouseOverLinkObject ) ) {
2005-01-29 12:32:59 +00:00
selectionClear ( ) ;
2015-08-27 20:09:02 +00:00
break ;
}
2017-09-21 20:16:31 +00:00
2005-06-13 11:28:15 +00:00
// if mouse is released and selection is null this is a rightClick
2005-06-24 16:41:55 +00:00
if ( rightButton & & ! d - > mouseSelecting ) {
2009-06-29 20:55:50 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2017-09-05 21:27:18 +00:00
emit rightClick ( pageItem ? pageItem - > page ( ) : nullptr , e - > globalPos ( ) ) ;
2005-06-13 11:28:15 +00:00
break ;
2005-03-05 15:59:15 +00:00
}
2005-06-13 11:28:15 +00:00
2005-01-29 12:32:59 +00:00
// if a selection is defined, display a popup
2005-03-24 19:10:41 +00:00
if ( ( ! leftButton & & ! d - > aPrevAction ) | | ( ! rightButton & & d - > aPrevAction ) | | ! d - > mouseSelecting )
2004-11-16 17:36:02 +00:00
break ;
2004-10-20 16:41:13 +00:00
2006-03-29 16:46:09 +00:00
QRect selectionRect = d - > mouseSelectionRect . normalized ( ) ;
2005-01-29 12:32:59 +00:00
if ( selectionRect . width ( ) < = 8 & & selectionRect . height ( ) < = 8 ) {
2005-01-02 10:46:33 +00:00
selectionClear ( ) ;
2005-01-29 12:32:59 +00:00
if ( d - > aPrevAction ) {
2006-03-24 20:40:02 +00:00
d - > aPrevAction - > trigger ( ) ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
2005-01-02 10:46:33 +00:00
}
2020-07-10 22:15:05 +00:00
break ;
}
2004-11-03 17:35:48 +00:00
2008-11-21 10:50:16 +00:00
// if we support text generation
2006-05-26 14:32:35 +00:00
QString selectedText ;
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
if ( d - > document - > supportsSearching ( ) ) {
2006-09-13 12:11:42 +00:00
// grab text in selection by extracting it from all intersected pages
2017-09-05 21:27:18 +00:00
const Okular : : Page * okularPage = nullptr ;
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * item : qAsConst ( d - > items ) ) {
2008-05-16 13:15:23 +00:00
if ( ! item - > isVisible ( ) )
continue ;
2008-05-19 00:37:14 +00:00
const QRect & itemRect = item - > croppedGeometry ( ) ;
2006-09-13 12:11:42 +00:00
if ( selectionRect . intersects ( itemRect ) ) {
// request the textpage if there isn't one
2006-09-21 08:45:36 +00:00
okularPage = item - > page ( ) ;
2017-01-14 18:15:26 +00:00
qCDebug ( OkularUiDebug ) < < " checking if page " < < item - > pageNumber ( ) < < " has text: " < < okularPage - > hasTextPage ( ) ;
2006-11-23 16:09:26 +00:00
if ( ! okularPage - > hasTextPage ( ) )
2006-09-21 08:45:36 +00:00
d - > document - > requestTextPage ( okularPage - > number ( ) ) ;
2006-09-13 12:11:42 +00:00
// grab text in the rect that intersects itemRect
2016-07-24 21:46:53 +00:00
QRect relativeRect = selectionRect . intersected ( itemRect ) ;
2008-05-19 00:37:14 +00:00
relativeRect . translate ( - item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
2006-12-24 18:19:18 +00:00
Okular : : RegularAreaRect rects ;
2008-05-19 00:37:14 +00:00
rects . append ( Okular : : NormalizedRect ( relativeRect , item - > uncroppedWidth ( ) , item - > uncroppedHeight ( ) ) ) ;
2006-12-24 18:19:18 +00:00
selectedText + = okularPage - > text ( & rects ) ;
2006-09-13 12:11:42 +00:00
}
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
}
2020-07-10 22:15:05 +00:00
}
2004-11-03 17:35:48 +00:00
2004-11-16 17:36:02 +00:00
// popup that ask to copy:text and copy/save:image
2014-08-13 10:45:40 +00:00
QMenu menu ( this ) ;
2019-04-25 21:10:48 +00:00
menu . setObjectName ( QStringLiteral ( " PopupMenu " ) ) ;
2017-09-05 21:27:18 +00:00
QAction * textToClipboard = nullptr ;
2015-08-18 13:28:38 +00:00
# ifdef HAVE_SPEECH
2017-09-05 21:27:18 +00:00
QAction * speakText = nullptr ;
2015-08-18 13:28:38 +00:00
# endif
2017-09-05 21:27:18 +00:00
QAction * imageToClipboard = nullptr ;
QAction * imageToFile = nullptr ;
2006-05-26 14:32:35 +00:00
if ( d - > document - > supportsSearching ( ) & & ! selectedText . isEmpty ( ) ) {
2016-12-28 16:03:28 +00:00
menu . addAction ( new OKMenuTitle ( & menu , i18np ( " Text (1 character) " , " Text (%1 characters) " , selectedText . length ( ) ) ) ) ;
2015-10-29 12:37:11 +00:00
textToClipboard = menu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-copy " ) ) , i18n ( " Copy to Clipboard " ) ) ;
2019-04-25 21:10:48 +00:00
textToClipboard - > setObjectName ( QStringLiteral ( " CopyTextToClipboard " ) ) ;
2010-09-11 13:52:01 +00:00
bool copyAllowed = d - > document - > isAllowed ( Okular : : AllowCopy ) ;
if ( ! copyAllowed ) {
2006-04-05 17:49:44 +00:00
textToClipboard - > setEnabled ( false ) ;
2006-05-19 18:22:54 +00:00
textToClipboard - > setText ( i18n ( " Copy forbidden by DRM " ) ) ;
}
2015-08-18 13:28:38 +00:00
# ifdef HAVE_SPEECH
2014-11-08 04:33:23 +00:00
if ( Okular : : Settings : : useTTS ( ) )
2015-10-29 12:37:11 +00:00
speakText = menu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " text-speak " ) ) , i18n ( " Speak Text " ) ) ;
2015-08-18 13:28:38 +00:00
# endif
2010-09-11 13:52:01 +00:00
if ( copyAllowed ) {
2019-08-25 10:19:43 +00:00
addSearchWithinDocumentAction ( & menu , selectedText ) ;
2010-09-11 13:52:01 +00:00
addWebShortcutsMenu ( & menu , selectedText ) ;
2004-11-16 17:36:02 +00:00
}
2020-07-10 22:15:05 +00:00
}
2016-12-28 16:03:28 +00:00
menu . addAction ( new OKMenuTitle ( & menu , i18n ( " Image (%1 by %2 pixels) " , selectionRect . width ( ) , selectionRect . height ( ) ) ) ) ;
2015-10-29 12:37:11 +00:00
imageToClipboard = menu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " image-x-generic " ) ) , i18n ( " Copy to Clipboard " ) ) ;
imageToFile = menu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " document-save " ) ) , i18n ( " Save to File... " ) ) ;
2006-03-24 20:40:02 +00:00
QAction * choice = menu . exec ( e - > globalPos ( ) ) ;
2006-06-02 10:32:29 +00:00
// check if the user really selected an action
2006-06-02 10:30:32 +00:00
if ( choice ) {
2006-10-21 22:07:05 +00:00
// IMAGE operation chosen
2006-03-24 20:40:02 +00:00
if ( choice = = imageToClipboard | | choice = = imageToFile ) {
2004-11-16 17:36:02 +00:00
// renders page into a pixmap
QPixmap copyPix ( selectionRect . width ( ) , selectionRect . height ( ) ) ;
QPainter copyPainter ( & copyPix ) ;
copyPainter . translate ( - selectionRect . left ( ) , - selectionRect . top ( ) ) ;
2005-04-01 16:24:11 +00:00
drawDocumentOnPainter ( selectionRect , & copyPainter ) ;
2008-06-06 22:03:30 +00:00
copyPainter . end ( ) ;
2004-11-16 17:36:02 +00:00
2006-03-24 20:40:02 +00:00
if ( choice = = imageToClipboard ) {
2004-11-16 17:36:02 +00:00
// [2] copy pixmap to clipboard
QClipboard * cb = QApplication : : clipboard ( ) ;
cb - > setPixmap ( copyPix , QClipboard : : Clipboard ) ;
if ( cb - > supportsSelection ( ) )
cb - > setPixmap ( copyPix , QClipboard : : Selection ) ;
2006-04-10 19:50:00 +00:00
d - > messageWindow - > display ( i18n ( " Image [%1x%2] copied to clipboard. " , copyPix . width ( ) , copyPix . height ( ) ) ) ;
2006-03-24 20:40:02 +00:00
} else if ( choice = = imageToFile ) {
2004-11-16 17:36:02 +00:00
// [3] save pixmap to file
2016-11-04 11:16:34 +00:00
QString fileName = QFileDialog : : getSaveFileName ( this , i18n ( " Save file " ) , QString ( ) , i18n ( " Images (*.png *.jpeg) " ) ) ;
2006-06-12 10:51:07 +00:00
if ( fileName . isEmpty ( ) )
2010-08-21 15:46:47 +00:00
d - > messageWindow - > display ( i18n ( " File not saved. " ) , QString ( ) , PageViewMessage : : Warning ) ;
2004-11-16 17:36:02 +00:00
else {
2014-09-11 13:18:05 +00:00
QMimeDatabase db ;
QMimeType mime = db . mimeTypeForUrl ( QUrl : : fromLocalFile ( fileName ) ) ;
2006-03-24 20:40:02 +00:00
QString type ;
2014-09-11 13:18:05 +00:00
if ( ! mime . isDefault ( ) )
2015-10-29 12:37:11 +00:00
type = QStringLiteral ( " PNG " ) ;
2006-03-24 20:40:02 +00:00
else
2016-07-11 20:05:18 +00:00
type = mime . name ( ) . section ( QLatin1Char ( ' / ' ) , - 1 ) . toUpper ( ) ;
2006-06-12 10:51:07 +00:00
copyPix . save ( fileName , qPrintable ( type ) ) ;
d - > messageWindow - > display ( i18n ( " Image [%1x%2] saved to %3 file. " , copyPix . width ( ) , copyPix . height ( ) , type ) ) ;
2004-11-03 17:35:48 +00:00
}
}
2004-10-20 16:41:13 +00:00
}
2006-10-21 22:07:05 +00:00
// TEXT operation chosen
2005-01-29 12:32:59 +00:00
else {
2006-03-24 20:40:02 +00:00
if ( choice = = textToClipboard ) {
2005-01-29 12:32:59 +00:00
// [1] copy text to clipboard
QClipboard * cb = QApplication : : clipboard ( ) ;
2006-05-26 14:32:35 +00:00
cb - > setText ( selectedText , QClipboard : : Clipboard ) ;
2005-01-29 12:32:59 +00:00
if ( cb - > supportsSelection ( ) )
2006-05-26 14:32:35 +00:00
cb - > setText ( selectedText , QClipboard : : Selection ) ;
2005-01-29 12:32:59 +00:00
}
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2006-03-24 20:40:02 +00:00
else if ( choice = = speakText ) {
2014-11-08 04:33:23 +00:00
// [2] speech selection using TTS
2008-03-05 02:13:09 +00:00
d - > tts ( ) - > say ( selectedText ) ;
2005-01-29 12:32:59 +00:00
}
2014-11-08 04:33:23 +00:00
# endif
2004-11-16 17:36:02 +00:00
}
2006-06-02 10:30:32 +00:00
}
2004-11-16 17:36:02 +00:00
// clear widget selection and invalidate rect
2005-01-29 12:32:59 +00:00
selectionClear ( ) ;
2020-07-10 22:15:05 +00:00
2005-01-28 17:21:28 +00:00
// restore previous action if came from it using right button
if ( d - > aPrevAction ) {
2006-03-24 20:40:02 +00:00
d - > aPrevAction - > trigger ( ) ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
2020-07-10 22:15:05 +00:00
}
} break ;
2012-03-09 17:43:40 +00:00
case Okular : : Settings : : EnumMouseMode : : TableSelect : {
2017-09-21 20:16:31 +00:00
// if it is a left release checks if is over a previous link press
if ( leftButton & & mouseReleaseOverLink ( d - > mouseOverLinkObject ) ) {
2004-11-16 17:36:02 +00:00
selectionClear ( ) ;
2020-07-10 22:15:05 +00:00
break ;
}
2011-10-12 13:50:56 +00:00
// if mouse is released and selection is null this is a rightClick
if ( rightButton & & ! d - > mouseSelecting ) {
2015-08-27 20:09:02 +00:00
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2017-09-05 21:27:18 +00:00
emit rightClick ( pageItem ? pageItem - > page ( ) : nullptr , e - > globalPos ( ) ) ;
2020-07-10 22:15:05 +00:00
break ;
}
2005-01-28 17:21:28 +00:00
QRect selectionRect = d - > mouseSelectionRect . normalized ( ) ;
if ( selectionRect . width ( ) < = 8 & & selectionRect . height ( ) < = 8 & & d - > tableSelectionParts . isEmpty ( ) ) {
2005-01-29 12:32:59 +00:00
selectionClear ( ) ;
2005-01-28 17:21:28 +00:00
if ( d - > aPrevAction ) {
2006-03-24 20:40:02 +00:00
d - > aPrevAction - > trigger ( ) ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
2005-01-28 17:21:28 +00:00
}
2017-09-21 20:16:31 +00:00
break ;
}
2011-10-12 13:50:56 +00:00
if ( d - > mouseSelecting ) {
// break up the selection into page-relative pieces
d - > tableSelectionParts . clear ( ) ;
const Okular : : Page * okularPage = nullptr ;
for ( PageViewItem * item : qAsConst ( d - > items ) ) {
2017-09-05 21:27:18 +00:00
if ( ! item - > isVisible ( ) )
continue ;
2011-10-12 13:50:56 +00:00
const QRect & itemRect = item - > croppedGeometry ( ) ;
if ( selectionRect . intersects ( itemRect ) ) {
// request the textpage if there isn't one
2006-09-21 08:45:36 +00:00
okularPage = item - > page ( ) ;
2017-01-14 18:15:26 +00:00
qCDebug ( OkularUiDebug ) < < " checking if page " < < item - > pageNumber ( ) < < " has text: " < < okularPage - > hasTextPage ( ) ;
2011-10-12 13:50:56 +00:00
if ( ! okularPage - > hasTextPage ( ) )
d - > document - > requestTextPage ( okularPage - > number ( ) ) ;
// grab text in the rect that intersects itemRect
2016-07-24 21:46:53 +00:00
QRect rectInItem = selectionRect . intersected ( itemRect ) ;
2011-10-12 13:50:56 +00:00
rectInItem . translate ( - item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
QRect rectInSelection = selectionRect . intersected ( itemRect ) ;
rectInSelection . translate ( - selectionRect . topLeft ( ) ) ;
d - > tableSelectionParts . append (
TableSelectionPart ( item , Okular : : NormalizedRect ( rectInItem , item - > uncroppedWidth ( ) , item - > uncroppedHeight ( ) ) , Okular : : NormalizedRect ( rectInSelection , selectionRect . width ( ) , selectionRect . height ( ) ) ) ) ;
}
}
QRect updatedRect = d - > mouseSelectionRect . normalized ( ) . adjusted ( 0 , 0 , 1 , 1 ) ;
updatedRect . translate ( - contentAreaPosition ( ) ) ;
d - > mouseSelecting = false ;
d - > mouseSelectionRect . setCoords ( 0 , 0 , 0 , 0 ) ;
d - > tableSelectionCols . clear ( ) ;
2019-03-26 22:37:30 +00:00
d - > tableSelectionRows . clear ( ) ;
guessTableDividers ( ) ;
viewport ( ) - > update ( updatedRect ) ;
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
2017-01-14 18:15:26 +00:00
if ( ! d - > document - > isAllowed ( Okular : : AllowCopy ) ) {
d - > messageWindow - > display ( i18n ( " Copy forbidden by DRM " ) , QString ( ) , PageViewMessage : : Info , - 1 ) ;
2011-10-12 13:50:56 +00:00
break ;
}
QString selText ;
QString selHtml ;
QList < double > xs = d - > tableSelectionCols ;
QList < double > ys = d - > tableSelectionRows ;
xs . prepend ( 0.0 ) ;
xs . append ( 1.0 ) ;
ys . prepend ( 0.0 ) ;
ys . append ( 1.0 ) ;
selHtml = QString : : fromLatin1 (
" <html><head> "
" <meta content= \" text/html; charset=utf-8 \" http-equiv= \" Content-Type \" > "
2015-10-29 12:37:11 +00:00
" </head><body><table> " ) ;
2011-10-12 13:50:56 +00:00
for ( int r = 0 ; r + 1 < ys . length ( ) ; r + + ) {
2015-10-29 12:37:11 +00:00
selHtml + = QLatin1String ( " <tr> " ) ;
2011-10-12 13:50:56 +00:00
for ( int c = 0 ; c + 1 < xs . length ( ) ; c + + ) {
Okular : : NormalizedRect cell ( xs [ c ] , ys [ r ] , xs [ c + 1 ] , ys [ r + 1 ] ) ;
2020-07-10 22:15:05 +00:00
if ( c )
2016-07-11 20:05:18 +00:00
selText + = QLatin1Char ( ' \t ' ) ;
2011-10-12 13:50:56 +00:00
QString txt ;
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-12 13:50:56 +00:00
// first, crop the cell to this part
if ( ! tsp . rectInSelection . intersects ( cell ) )
continue ;
Okular : : NormalizedRect cellPart = tsp . rectInSelection & cell ; // intersection
2020-07-10 22:15:05 +00:00
2011-10-12 13:50:56 +00:00
// second, convert it from table coordinates to part coordinates
cellPart . left - = tsp . rectInSelection . left ;
cellPart . left / = ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
cellPart . right - = tsp . rectInSelection . left ;
cellPart . right / = ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
cellPart . top - = tsp . rectInSelection . top ;
cellPart . top / = ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
cellPart . bottom - = tsp . rectInSelection . top ;
cellPart . bottom / = ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
2020-07-10 22:15:05 +00:00
2011-10-12 13:50:56 +00:00
// third, convert from part coordinates to item coordinates
cellPart . left * = ( tsp . rectInItem . right - tsp . rectInItem . left ) ;
cellPart . left + = tsp . rectInItem . left ;
cellPart . right * = ( tsp . rectInItem . right - tsp . rectInItem . left ) ;
cellPart . right + = tsp . rectInItem . left ;
cellPart . top * = ( tsp . rectInItem . bottom - tsp . rectInItem . top ) ;
cellPart . top + = tsp . rectInItem . top ;
cellPart . bottom * = ( tsp . rectInItem . bottom - tsp . rectInItem . top ) ;
cellPart . bottom + = tsp . rectInItem . top ;
2020-07-10 22:15:05 +00:00
2011-10-12 13:50:56 +00:00
// now get the text
Okular : : RegularAreaRect rects ;
rects . append ( cellPart ) ;
txt + = tsp . item - > page ( ) - > text ( & rects , Okular : : TextPage : : CentralPixelTextAreaInclusionBehaviour ) ;
2020-07-10 22:15:05 +00:00
}
2011-10-12 13:50:56 +00:00
QString html = txt ;
selText + = txt . replace ( QLatin1Char ( ' \n ' ) , QLatin1Char ( ' ' ) ) ;
2016-07-11 20:05:18 +00:00
html . replace ( QLatin1Char ( ' & ' ) , QLatin1String ( " & " ) ) . replace ( QLatin1Char ( ' < ' ) , QLatin1String ( " < " ) ) . replace ( QLatin1Char ( ' > ' ) , QLatin1String ( " > " ) ) ;
2011-10-12 13:50:56 +00:00
// Remove newlines, do not turn them into <br>, because
// Excel interprets <br> within cell as new cell...
html . replace ( QLatin1Char ( ' \n ' ) , QLatin1String ( " " ) ) ;
selHtml + = QStringLiteral ( " <td> " ) + html + QStringLiteral ( " </td> " ) ;
}
2016-07-11 20:05:18 +00:00
selText + = QLatin1Char ( ' \n ' ) ;
2015-10-29 12:37:11 +00:00
selHtml + = QLatin1String ( " </tr> \n " ) ;
2020-07-10 22:15:05 +00:00
}
2015-10-29 12:37:11 +00:00
selHtml + = QLatin1String ( " </table></body></html> \n " ) ;
2011-10-12 13:50:56 +00:00
QClipboard * cb = QApplication : : clipboard ( ) ;
QMimeData * md = new QMimeData ( ) ;
md - > setText ( selText ) ;
md - > setHtml ( selHtml ) ;
cb - > setMimeData ( md , QClipboard : : Clipboard ) ;
if ( cb - > supportsSelection ( ) )
cb - > setMimeData ( md , QClipboard : : Selection ) ;
2020-07-10 22:15:05 +00:00
} break ;
2011-10-12 13:50:56 +00:00
case Okular : : Settings : : EnumMouseMode : : TextSelect :
// if it is a left release checks if is over a previous link press
if ( leftButton & & mouseReleaseOverLink ( d - > mouseOverLinkObject ) ) {
selectionClear ( ) ;
break ;
}
if ( d - > mouseTextSelecting ) {
d - > mouseTextSelecting = false ;
2019-12-09 13:39:47 +00:00
// textSelectionClear();
2011-10-12 13:50:56 +00:00
if ( d - > document - > isAllowed ( Okular : : AllowCopy ) ) {
const QString text = d - > selectedText ( ) ;
if ( ! text . isEmpty ( ) ) {
QClipboard * cb = QApplication : : clipboard ( ) ;
if ( cb - > supportsSelection ( ) )
cb - > setText ( text , QClipboard : : Selection ) ;
}
}
} else if ( ! d - > mousePressPos . isNull ( ) & & rightButton ) {
2012-03-09 17:43:40 +00:00
PageViewItem * item = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
const Okular : : Page * page ;
2017-09-21 20:16:31 +00:00
// if there is text selected in the page
if ( item ) {
2008-03-04 00:01:46 +00:00
QAction * httpLink = nullptr ;
QAction * textToClipboard = nullptr ;
2017-09-21 20:16:31 +00:00
QString url ;
2020-07-10 22:15:05 +00:00
2017-09-21 20:16:31 +00:00
QMenu * menu = createProcessLinkMenu ( item , eventPos ) ;
const bool mouseClickOverLink = ( menu ! = nullptr ) ;
2015-03-17 07:51:36 +00:00
# ifdef HAVE_SPEECH
2017-09-05 21:27:18 +00:00
QAction * speakText = nullptr ;
2015-03-17 07:51:36 +00:00
# endif
2017-09-21 20:16:31 +00:00
if ( ( page = item - > page ( ) ) - > textSelection ( ) ) {
if ( ! menu ) {
menu = new QMenu ( this ) ;
}
textToClipboard = menu - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-copy " ) ) , i18n ( " Copy Text " ) ) ;
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2017-09-21 20:16:31 +00:00
if ( Okular : : Settings : : useTTS ( ) )
speakText = menu - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " text-speak " ) ) , i18n ( " Speak Text " ) ) ;
# endif
if ( ! d - > document - > isAllowed ( Okular : : AllowCopy ) ) {
textToClipboard - > setEnabled ( false ) ;
textToClipboard - > setText ( i18n ( " Copy forbidden by DRM " ) ) ;
} else {
2019-08-25 10:19:43 +00:00
addSearchWithinDocumentAction ( menu , d - > selectedText ( ) ) ;
2017-09-21 20:16:31 +00:00
addWebShortcutsMenu ( menu , d - > selectedText ( ) ) ;
2011-08-14 02:57:15 +00:00
}
2017-09-21 20:16:31 +00:00
// if the right-click was over a link add "Follow This link" instead of "Go to"
if ( ! mouseClickOverLink ) {
url = UrlUtils : : getUrl ( d - > selectedText ( ) ) ;
if ( ! url . isEmpty ( ) ) {
2019-08-25 10:19:43 +00:00
const QString squeezedText = KStringHandler : : rsqueeze ( url , linkTextPreviewLength ) ;
2017-09-21 20:16:31 +00:00
httpLink = menu - > addAction ( i18n ( " Go to '%1' " , squeezedText ) ) ;
2019-04-25 21:10:48 +00:00
httpLink - > setObjectName ( QStringLiteral ( " GoToAction " ) ) ;
2017-09-21 20:16:31 +00:00
}
2020-07-10 22:15:05 +00:00
}
}
2017-09-21 20:16:31 +00:00
if ( menu ) {
2019-04-25 21:10:48 +00:00
menu - > setObjectName ( QStringLiteral ( " PopupMenu " ) ) ;
2017-09-21 20:16:31 +00:00
QAction * choice = menu - > exec ( e - > globalPos ( ) ) ;
// check if the user really selected an action
if ( choice ) {
if ( choice = = textToClipboard )
copyTextSelection ( ) ;
# ifdef HAVE_SPEECH
else if ( choice = = speakText ) {
const QString text = d - > selectedText ( ) ;
d - > tts ( ) - > say ( text ) ;
}
2014-11-08 04:33:23 +00:00
# endif
2017-09-21 20:16:31 +00:00
else if ( choice = = httpLink ) {
new KRun ( QUrl ( url ) , this ) ;
2008-03-05 11:06:55 +00:00
}
2006-09-26 22:22:01 +00:00
}
2020-07-10 22:15:05 +00:00
2017-09-21 20:16:31 +00:00
menu - > deleteLater ( ) ;
2006-09-26 22:22:01 +00:00
}
2020-07-10 22:15:05 +00:00
}
}
2006-09-26 22:22:01 +00:00
break ;
2004-09-26 23:39:39 +00:00
}
2005-01-29 12:32:59 +00:00
// reset mouse press / 'drag start' position
d - > mousePressPos = QPoint ( ) ;
2004-09-26 23:39:39 +00:00
}
2011-10-31 15:33:03 +00:00
void PageView : : guessTableDividers ( )
{
QList < QPair < double , int > > colTicks , rowTicks , colSelectionTicks , rowSelectionTicks ;
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-31 15:33:03 +00:00
// add ticks for the edges of this area...
colSelectionTicks . append ( qMakePair ( tsp . rectInSelection . left , + 1 ) ) ;
colSelectionTicks . append ( qMakePair ( tsp . rectInSelection . right , - 1 ) ) ;
rowSelectionTicks . append ( qMakePair ( tsp . rectInSelection . top , + 1 ) ) ;
rowSelectionTicks . append ( qMakePair ( tsp . rectInSelection . bottom , - 1 ) ) ;
// get the words in this part
Okular : : RegularAreaRect rects ;
rects . append ( tsp . rectInItem ) ;
const Okular : : TextEntity : : List words = tsp . item - > page ( ) - > words ( & rects , Okular : : TextPage : : CentralPixelTextAreaInclusionBehaviour ) ;
2019-12-09 13:39:47 +00:00
for ( const Okular : : TextEntity * te : words ) {
2011-10-31 15:33:03 +00:00
if ( te - > text ( ) . isEmpty ( ) ) {
delete te ;
continue ;
}
Okular : : NormalizedRect wordArea = * te - > area ( ) ;
// convert it from item coordinates to part coordinates
wordArea . left - = tsp . rectInItem . left ;
wordArea . left / = ( tsp . rectInItem . right - tsp . rectInItem . left ) ;
wordArea . right - = tsp . rectInItem . left ;
wordArea . right / = ( tsp . rectInItem . right - tsp . rectInItem . left ) ;
wordArea . top - = tsp . rectInItem . top ;
wordArea . top / = ( tsp . rectInItem . bottom - tsp . rectInItem . top ) ;
wordArea . bottom - = tsp . rectInItem . top ;
wordArea . bottom / = ( tsp . rectInItem . bottom - tsp . rectInItem . top ) ;
// convert from part coordinates to table coordinates
wordArea . left * = ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
wordArea . left + = tsp . rectInSelection . left ;
wordArea . right * = ( tsp . rectInSelection . right - tsp . rectInSelection . left ) ;
wordArea . right + = tsp . rectInSelection . left ;
wordArea . top * = ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
wordArea . top + = tsp . rectInSelection . top ;
wordArea . bottom * = ( tsp . rectInSelection . bottom - tsp . rectInSelection . top ) ;
wordArea . bottom + = tsp . rectInSelection . top ;
// add to the ticks arrays...
colTicks . append ( qMakePair ( wordArea . left , + 1 ) ) ;
colTicks . append ( qMakePair ( wordArea . right , - 1 ) ) ;
rowTicks . append ( qMakePair ( wordArea . top , + 1 ) ) ;
rowTicks . append ( qMakePair ( wordArea . bottom , - 1 ) ) ;
delete te ;
}
}
int tally = 0 ;
2019-03-12 12:13:53 +00:00
std : : sort ( colSelectionTicks . begin ( ) , colSelectionTicks . end ( ) ) ;
std : : sort ( rowSelectionTicks . begin ( ) , rowSelectionTicks . end ( ) ) ;
2011-10-31 15:33:03 +00:00
for ( int i = 0 ; i < colSelectionTicks . length ( ) ; + + i ) {
tally + = colSelectionTicks [ i ] . second ;
if ( tally = = 0 & & i + 1 < colSelectionTicks . length ( ) & & colSelectionTicks [ i + 1 ] . first ! = colSelectionTicks [ i ] . first ) {
colTicks . append ( qMakePair ( colSelectionTicks [ i ] . first , + 1 ) ) ;
colTicks . append ( qMakePair ( colSelectionTicks [ i + 1 ] . first , - 1 ) ) ;
}
}
Q_ASSERT ( tally = = 0 ) ;
for ( int i = 0 ; i < rowSelectionTicks . length ( ) ; + + i ) {
tally + = rowSelectionTicks [ i ] . second ;
if ( tally = = 0 & & i + 1 < rowSelectionTicks . length ( ) & & rowSelectionTicks [ i + 1 ] . first ! = rowSelectionTicks [ i ] . first ) {
rowTicks . append ( qMakePair ( rowSelectionTicks [ i ] . first , + 1 ) ) ;
rowTicks . append ( qMakePair ( rowSelectionTicks [ i + 1 ] . first , - 1 ) ) ;
}
}
Q_ASSERT ( tally = = 0 ) ;
2019-03-12 12:13:53 +00:00
std : : sort ( colTicks . begin ( ) , colTicks . end ( ) ) ;
std : : sort ( rowTicks . begin ( ) , rowTicks . end ( ) ) ;
2011-10-31 15:33:03 +00:00
for ( int i = 0 ; i < colTicks . length ( ) ; + + i ) {
tally + = colTicks [ i ] . second ;
if ( tally = = 0 & & i + 1 < colTicks . length ( ) & & colTicks [ i + 1 ] . first ! = colTicks [ i ] . first ) {
d - > tableSelectionCols . append ( ( colTicks [ i ] . first + colTicks [ i + 1 ] . first ) / 2 ) ;
d - > tableDividersGuessed = true ;
}
}
Q_ASSERT ( tally = = 0 ) ;
for ( int i = 0 ; i < rowTicks . length ( ) ; + + i ) {
tally + = rowTicks [ i ] . second ;
if ( tally = = 0 & & i + 1 < rowTicks . length ( ) & & rowTicks [ i + 1 ] . first ! = rowTicks [ i ] . first ) {
d - > tableSelectionRows . append ( ( rowTicks [ i ] . first + rowTicks [ i + 1 ] . first ) / 2 ) ;
d - > tableDividersGuessed = true ;
}
}
Q_ASSERT ( tally = = 0 ) ;
}
2010-03-23 20:21:42 +00:00
void PageView : : mouseDoubleClickEvent ( QMouseEvent * e )
{
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta = 0 ;
2010-03-23 20:21:42 +00:00
if ( e - > button ( ) = = Qt : : LeftButton ) {
const QPoint eventPos = contentAreaPoint ( e - > pos ( ) ) ;
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
if ( pageItem ) {
// find out normalized mouse coords inside current item
double nX = pageItem - > absToPageX ( eventPos . x ( ) ) ;
double nY = pageItem - > absToPageY ( eventPos . y ( ) ) ;
2012-03-25 21:48:07 +00:00
2014-12-10 14:33:27 +00:00
if ( d - > mouseMode = = Okular : : Settings : : EnumMouseMode : : TextSelect ) {
2012-03-25 21:48:07 +00:00
textSelectionClear ( ) ;
2013-04-05 22:22:48 +00:00
2012-03-25 21:48:07 +00:00
Okular : : RegularAreaRect * wordRect = pageItem - > page ( ) - > wordAt ( Okular : : NormalizedPoint ( nX , nY ) ) ;
if ( wordRect ) {
// TODO words with hyphens across pages
d - > document - > setPageTextSelection ( pageItem - > pageNumber ( ) , wordRect , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) ) ;
d - > pagesWithTextSelection < < pageItem - > pageNumber ( ) ;
2012-10-16 18:38:55 +00:00
if ( d - > document - > isAllowed ( Okular : : AllowCopy ) ) {
const QString text = d - > selectedText ( ) ;
if ( ! text . isEmpty ( ) ) {
QClipboard * cb = QApplication : : clipboard ( ) ;
if ( cb - > supportsSelection ( ) )
cb - > setText ( text , QClipboard : : Selection ) ;
}
2012-10-16 18:36:52 +00:00
}
2012-03-25 21:48:07 +00:00
return ;
}
}
2013-04-05 22:22:48 +00:00
2012-03-25 21:48:07 +00:00
const QRect & itemRect = pageItem - > uncroppedGeometry ( ) ;
2017-09-05 21:27:18 +00:00
Okular : : Annotation * ann = nullptr ;
2010-03-23 20:21:42 +00:00
const Okular : : ObjectRect * orect = pageItem - > page ( ) - > objectRect ( Okular : : ObjectRect : : OAnnotation , nX , nY , itemRect . width ( ) , itemRect . height ( ) ) ;
if ( orect )
ann = ( ( Okular : : AnnotationObjectRect * ) orect ) - > annotation ( ) ;
2012-12-10 18:07:31 +00:00
if ( ann & & ann - > subType ( ) ! = Okular : : Annotation : : AWidget ) {
2012-01-17 22:46:37 +00:00
openAnnotationWindow ( ann , pageItem - > pageNumber ( ) ) ;
2010-03-23 20:21:42 +00:00
}
}
}
}
2004-09-26 23:39:39 +00:00
void PageView : : wheelEvent ( QWheelEvent * e )
{
2006-10-26 20:59:07 +00:00
if ( ! d - > document - > isOpened ( ) ) {
2009-06-29 20:55:50 +00:00
QAbstractScrollArea : : wheelEvent ( e ) ;
2006-10-26 20:59:07 +00:00
return ;
}
2004-10-29 21:52:06 +00:00
int delta = e - > angleDelta ( ) . y ( ) , vScroll = verticalScrollBar ( ) - > value ( ) ;
2004-09-26 23:39:39 +00:00
e - > accept ( ) ;
2006-09-26 22:22:01 +00:00
if ( ( e - > modifiers ( ) & Qt : : ControlModifier ) = = Qt : : ControlModifier ) {
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta + = delta ;
if ( d - > controlWheelAccumulatedDelta < = - QWheelEvent : : DefaultDeltasPerStep ) {
2004-09-26 23:39:39 +00:00
slotZoomOut ( ) ;
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta = 0 ;
} else if ( d - > controlWheelAccumulatedDelta > = QWheelEvent : : DefaultDeltasPerStep ) {
2004-09-26 23:39:39 +00:00
slotZoomIn ( ) ;
2017-03-03 22:55:06 +00:00
d - > controlWheelAccumulatedDelta = 0 ;
}
} else {
d - > controlWheelAccumulatedDelta = 0 ;
if ( delta < = - QWheelEvent : : DefaultDeltasPerStep & & ! Okular : : Settings : : viewContinuous ( ) & & vScroll = = verticalScrollBar ( ) - > maximum ( ) ) {
// go to next page
if ( ( int ) d - > document - > currentPage ( ) < d - > items . count ( ) - 1 ) {
// more optimized than document->setNextPage and then move view to top
Okular : : DocumentViewport newViewport = d - > document - > viewport ( ) ;
newViewport . pageNumber + = viewColumns ( ) ;
if ( newViewport . pageNumber > = ( int ) d - > items . count ( ) )
newViewport . pageNumber = d - > items . count ( ) - 1 ;
newViewport . rePos . enabled = true ;
newViewport . rePos . normalizedY = 0.0 ;
d - > document - > setViewport ( newViewport ) ;
2019-11-15 16:08:25 +00:00
d - > scroller - > scrollTo ( QPoint ( horizontalScrollBar ( ) - > value ( ) , verticalScrollBar ( ) - > value ( ) ) , 0 ) ; // sync scroller with scrollbar
2017-03-03 22:55:06 +00:00
}
} else if ( delta > = QWheelEvent : : DefaultDeltasPerStep & & ! Okular : : Settings : : viewContinuous ( ) & & vScroll = = verticalScrollBar ( ) - > minimum ( ) ) {
// go to prev page
if ( d - > document - > currentPage ( ) > 0 ) {
// more optimized than document->setPrevPage and then move view to bottom
Okular : : DocumentViewport newViewport = d - > document - > viewport ( ) ;
newViewport . pageNumber - = viewColumns ( ) ;
if ( newViewport . pageNumber < 0 )
newViewport . pageNumber = 0 ;
newViewport . rePos . enabled = true ;
newViewport . rePos . normalizedY = 1.0 ;
d - > document - > setViewport ( newViewport ) ;
2019-11-15 16:08:25 +00:00
d - > scroller - > scrollTo ( QPoint ( horizontalScrollBar ( ) - > value ( ) , verticalScrollBar ( ) - > value ( ) ) , 0 ) ; // sync scroller with scrollbar
}
} else {
2020-10-21 01:03:38 +00:00
// When the shift key is held down, scroll ten times faster
int multiplier = e - > modifiers ( ) & Qt : : ShiftModifier ? 10 : 1 ;
2019-11-15 16:08:25 +00:00
if ( delta ! = 0 & & delta % QWheelEvent : : DefaultDeltasPerStep = = 0 ) {
// number of scroll wheel steps Qt gives to us at the same time
2020-10-21 01:03:38 +00:00
int count = abs ( delta / QWheelEvent : : DefaultDeltasPerStep ) * multiplier ;
2019-11-15 16:08:25 +00:00
if ( delta < 0 ) {
slotScrollDown ( count ) ;
} else {
slotScrollUp ( count ) ;
}
} else {
2020-10-21 01:03:38 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) - e - > angleDelta ( ) * multiplier / 4.0 , 0 ) ;
2017-03-03 22:55:06 +00:00
}
2004-12-12 22:57:54 +00:00
}
2004-10-29 21:52:06 +00:00
}
2004-09-30 18:16:12 +00:00
}
2009-06-29 20:55:50 +00:00
bool PageView : : viewportEvent ( QEvent * e )
{
2018-08-28 09:06:22 +00:00
if ( e - > type ( ) = = QEvent : : ToolTip
// Show tool tips only for those modes that change the cursor
// to a hand when hovering over the link.
& & ( d - > mouseMode = = Okular : : Settings : : EnumMouseMode : : Browse | | d - > mouseMode = = Okular : : Settings : : EnumMouseMode : : RectSelect | | d - > mouseMode = = Okular : : Settings : : EnumMouseMode : : TextSelect | |
d - > mouseMode = = Okular : : Settings : : EnumMouseMode : : TrimSelect ) ) {
2009-06-29 20:55:50 +00:00
QHelpEvent * he = static_cast < QHelpEvent * > ( e ) ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
if ( d - > mouseAnnotation - > isMouseOver ( ) ) {
d - > mouseAnnotation - > routeTooltipEvent ( he ) ;
} else {
const QPoint eventPos = contentAreaPoint ( he - > pos ( ) ) ;
PageViewItem * pageItem = pickItemOnPoint ( eventPos . x ( ) , eventPos . y ( ) ) ;
2017-09-05 21:27:18 +00:00
const Okular : : ObjectRect * rect = nullptr ;
const Okular : : Action * link = nullptr ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
if ( pageItem ) {
double nX = pageItem - > absToPageX ( eventPos . x ( ) ) ;
double nY = pageItem - > absToPageY ( eventPos . y ( ) ) ;
2009-06-29 20:55:50 +00:00
rect = pageItem - > page ( ) - > objectRect ( Okular : : ObjectRect : : Action , nX , nY , pageItem - > uncroppedWidth ( ) , pageItem - > uncroppedHeight ( ) ) ;
if ( rect )
link = static_cast < const Okular : : Action * > ( rect - > object ( ) ) ;
}
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
if ( link ) {
QRect r = rect - > boundingRect ( pageItem - > uncroppedWidth ( ) , pageItem - > uncroppedHeight ( ) ) ;
r . translate ( pageItem - > uncroppedGeometry ( ) . topLeft ( ) ) ;
r . translate ( - contentAreaPosition ( ) ) ;
QString tip = link - > actionTip ( ) ;
if ( ! tip . isEmpty ( ) )
QToolTip : : showText ( he - > globalPos ( ) , tip , viewport ( ) , r ) ;
}
2009-06-29 20:55:50 +00:00
}
e - > accept ( ) ;
return true ;
} else
// do not stop the event
return QAbstractScrollArea : : viewportEvent ( e ) ;
}
2009-07-07 16:53:33 +00:00
void PageView : : scrollContentsBy ( int dx , int dy )
{
const QRect r = viewport ( ) - > rect ( ) ;
viewport ( ) - > scroll ( dx , dy , r ) ;
// HACK manually repaint the damaged regions, as it seems some updates are missed
// thus leaving artifacts around
QRegion rgn ( r ) ;
rgn - = rgn & r . translated ( dx , dy ) ;
2019-07-22 21:39:13 +00:00
2019-07-23 14:48:52 +00:00
for ( const QRect & rect : rgn )
2019-07-22 21:39:13 +00:00
viewport ( ) - > update ( rect ) ;
2020-10-21 00:40:01 +00:00
updateCursor ( ) ;
2009-07-07 16:53:33 +00:00
}
2004-09-26 23:39:39 +00:00
// END widget events
2020-02-20 17:45:46 +00:00
QList < Okular : : RegularAreaRect * > PageView : : textSelections ( const QPoint start , const QPoint end , int & firstpage )
2006-10-03 17:13:42 +00:00
{
firstpage = - 1 ;
QList < Okular : : RegularAreaRect * > ret ;
QSet < int > affectedItemsSet ;
QRect selectionRect = QRect ( start , end ) . normalized ( ) ;
2019-12-09 13:39:47 +00:00
for ( const PageViewItem * item : qAsConst ( d - > items ) ) {
2008-05-19 00:37:14 +00:00
if ( item - > isVisible ( ) & & selectionRect . intersects ( item - > croppedGeometry ( ) ) )
2006-10-03 17:13:42 +00:00
affectedItemsSet . insert ( item - > pageNumber ( ) ) ;
}
2006-12-23 16:36:08 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < " >>>> item selected by mouse: " < < affectedItemsSet . count ( ) ;
2006-12-23 16:36:08 +00:00
# endif
2006-10-03 17:13:42 +00:00
if ( ! affectedItemsSet . isEmpty ( ) ) {
// is the mouse drag line the ne-sw diagonal of the selection rect?
bool direction_ne_sw = start = = selectionRect . topRight ( ) | | start = = selectionRect . bottomLeft ( ) ;
int tmpmin = d - > document - > pages ( ) ;
int tmpmax = 0 ;
2019-12-09 13:39:47 +00:00
for ( const int p : qAsConst ( affectedItemsSet ) ) {
2006-10-03 17:13:42 +00:00
if ( p < tmpmin )
tmpmin = p ;
if ( p > tmpmax )
tmpmax = p ;
}
PageViewItem * a = pickItemOnPoint ( ( int ) ( direction_ne_sw ? selectionRect . right ( ) : selectionRect . left ( ) ) , ( int ) selectionRect . top ( ) ) ;
int min = a & & ( a - > pageNumber ( ) ! = tmpmax ) ? a - > pageNumber ( ) : tmpmin ;
PageViewItem * b = pickItemOnPoint ( ( int ) ( direction_ne_sw ? selectionRect . left ( ) : selectionRect . right ( ) ) , ( int ) selectionRect . bottom ( ) ) ;
int max = b & & ( b - > pageNumber ( ) ! = tmpmin ) ? b - > pageNumber ( ) : tmpmax ;
QList < int > affectedItemsIds ;
for ( int i = min ; i < = max ; + + i )
affectedItemsIds . append ( i ) ;
2006-12-23 16:36:08 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < " >>>> pages: " < < affectedItemsIds ;
2006-12-23 16:36:08 +00:00
# endif
2006-10-03 17:13:42 +00:00
firstpage = affectedItemsIds . first ( ) ;
if ( affectedItemsIds . count ( ) = = 1 ) {
PageViewItem * item = d - > items [ affectedItemsIds . first ( ) ] ;
2008-05-19 00:37:14 +00:00
selectionRect . translate ( - item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
2006-10-03 17:13:42 +00:00
ret . append ( textSelectionForItem ( item , direction_ne_sw ? selectionRect . topRight ( ) : selectionRect . topLeft ( ) , direction_ne_sw ? selectionRect . bottomLeft ( ) : selectionRect . bottomRight ( ) ) ) ;
} else if ( affectedItemsIds . count ( ) > 1 ) {
// first item
PageViewItem * first = d - > items [ affectedItemsIds . first ( ) ] ;
2016-07-24 21:46:53 +00:00
QRect geom = first - > croppedGeometry ( ) . intersected ( selectionRect ) . translated ( - first - > uncroppedGeometry ( ) . topLeft ( ) ) ;
2006-10-03 17:13:42 +00:00
ret . append ( textSelectionForItem ( first , selectionRect . bottom ( ) > geom . height ( ) ? ( direction_ne_sw ? geom . topRight ( ) : geom . topLeft ( ) ) : ( direction_ne_sw ? geom . bottomRight ( ) : geom . bottomLeft ( ) ) , QPoint ( ) ) ) ;
// last item
PageViewItem * last = d - > items [ affectedItemsIds . last ( ) ] ;
2016-07-24 21:46:53 +00:00
geom = last - > croppedGeometry ( ) . intersected ( selectionRect ) . translated ( - last - > uncroppedGeometry ( ) . topLeft ( ) ) ;
2006-10-03 17:13:42 +00:00
// the last item needs to appended at last...
Okular : : RegularAreaRect * lastArea =
textSelectionForItem ( last , QPoint ( ) , selectionRect . bottom ( ) > geom . height ( ) ? ( direction_ne_sw ? geom . bottomLeft ( ) : geom . bottomRight ( ) ) : ( direction_ne_sw ? geom . topLeft ( ) : geom . topRight ( ) ) ) ;
affectedItemsIds . removeFirst ( ) ;
affectedItemsIds . removeLast ( ) ;
// item between the two above
2019-12-09 13:39:47 +00:00
for ( const int page : qAsConst ( affectedItemsIds ) ) {
2006-10-03 17:13:42 +00:00
ret . append ( textSelectionForItem ( d - > items [ page ] ) ) ;
}
ret . append ( lastArea ) ;
}
}
return ret ;
}
2020-02-20 17:45:46 +00:00
void PageView : : drawDocumentOnPainter ( const QRect contentsRect , QPainter * p )
2004-10-30 20:54:48 +00:00
{
Custom background color
Summary:
BUG: 182994
Adds an option to the config dialog that enables background color (the color around the displayed page) to be changed (while by default preserving the Qt toolkit selection as not to affect existing users).
Reasons for this change:
Accessibility, eye strain, aesthetic reasons, color displayed on monitor can affect power consumption (how: depends on display technology).
Many people want this change occording to Bugzilla and other sources.
Maintenance: Nearly no additional maintenance:
This is no new subsystem but a trivial feature with no complex code dependencies, and we are already showing a colour selection dialog and setting colours in other places in Okular.
{F4257766}
Other less important information:
https://git.reviewboard.kde.org/r/130219/
https://mail.kde.org/pipermail/okular-devel/2017-September/025520.html
Test Plan:
Tested everything, it all works:
Toggled the custom background color, changed custom background color, removed okular settings file (with: "rm ~/.config/okular*") to verify it uses the usual qt theme colour by default (where the settings file remembered the custom color).
Reviewers: #okular, aacid, elvisangelaccio, rkflx, ngraham
Reviewed By: ngraham
Subscribers: aacid, ltoscano, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D8051
2017-10-01 09:29:25 +00:00
QColor backColor ;
if ( Okular : : Settings : : useCustomBackgroundColor ( ) )
backColor = Okular : : Settings : : backgroundColor ( ) ;
else
backColor = viewport ( ) - > palette ( ) . color ( QPalette : : Dark ) ;
2011-02-09 21:24:09 +00:00
2006-10-21 22:07:05 +00:00
// create a region from which we'll subtract painted rects
2004-11-03 17:35:48 +00:00
QRegion remainingArea ( contentsRect ) ;
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
// This loop draws the actual pages
2005-04-01 16:24:11 +00:00
// iterate over all items painting the ones intersecting contentsRect
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * item : qAsConst ( d - > items ) ) {
2004-10-30 20:54:48 +00:00
// check if a piece of the page intersects the contents rect
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
if ( ! item - > isVisible ( ) | | ! item - > croppedGeometry ( ) . intersects ( contentsRect ) )
2004-11-05 18:14:20 +00:00
continue ;
2004-10-30 20:54:48 +00:00
2005-04-01 16:24:11 +00:00
// get item and item's outline geometries
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
QRect itemGeometry = item - > croppedGeometry ( ) ;
2004-10-30 20:54:48 +00:00
2008-05-19 00:37:14 +00:00
// move the painter to the top-left corner of the real page
2004-11-05 18:14:20 +00:00
p - > save ( ) ;
2005-04-01 16:24:11 +00:00
p - > translate ( itemGeometry . left ( ) , itemGeometry . top ( ) ) ;
2004-11-05 18:14:20 +00:00
2006-10-21 22:07:05 +00:00
// draw the page using the PagePainter with all flags active
2005-04-01 16:24:11 +00:00
if ( contentsRect . intersects ( itemGeometry ) ) {
2017-09-05 21:27:18 +00:00
Okular : : NormalizedPoint * viewPortPoint = nullptr ;
2011-10-17 19:56:45 +00:00
Okular : : NormalizedPoint point ( d - > lastSourceLocationViewportNormalizedX , d - > lastSourceLocationViewportNormalizedY ) ;
if ( Okular : : Settings : : showSourceLocationsGraphically ( ) & & item - > pageNumber ( ) = = d - > lastSourceLocationViewportPageNumber ) {
viewPortPoint = & point ;
}
2016-07-24 21:46:53 +00:00
QRect pixmapRect = contentsRect . intersected ( itemGeometry ) ;
2008-05-19 00:37:14 +00:00
pixmapRect . translate ( - item - > croppedGeometry ( ) . topLeft ( ) ) ;
2013-02-24 21:58:53 +00:00
PagePainter : : paintCroppedPageOnPainter ( p , item - > page ( ) , this , pageflags , item - > uncroppedWidth ( ) , item - > uncroppedHeight ( ) , pixmapRect , item - > crop ( ) , viewPortPoint ) ;
2004-10-30 20:54:48 +00:00
}
2004-11-05 18:14:20 +00:00
// remove painted area from 'remainingArea' and restore painter
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
remainingArea - = itemGeometry ;
2004-11-05 18:14:20 +00:00
p - > restore ( ) ;
2004-10-30 20:54:48 +00:00
}
2004-11-03 17:35:48 +00:00
2019-06-29 19:43:12 +00:00
// fill the visible area around the page with the background color
for ( const QRect & backRect : remainingArea )
p - > fillRect ( backRect , backColor ) ;
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
// take outline and shadow into account when testing whether a repaint is necessary
auto dpr = devicePixelRatioF ( ) ;
QRect checkRect = contentsRect ;
checkRect . adjust ( - 3 , - 3 , 1 , 1 ) ;
2019-07-13 05:57:59 +00:00
// Method to linearly interpolate between black (=(0,0,0), omitted) and the background color
auto interpolateColor = [ & backColor ] ( double t ) { return QColor ( t * backColor . red ( ) , t * backColor . green ( ) , t * backColor . blue ( ) ) ; } ;
// width of the shadow in device pixels
static const int shadowWidth = 2 * dpr ;
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
// iterate over all items painting a black outline and a simple bottom/right gradient
for ( const PageViewItem * item : qAsConst ( d - > items ) ) {
// check if a piece of the page intersects the contents rect
if ( ! item - > isVisible ( ) | | ! item - > croppedGeometry ( ) . intersects ( checkRect ) )
continue ;
// get item and item's outline geometries
QRect itemGeometry = item - > croppedGeometry ( ) ;
// move the painter to the top-left corner of the real page
p - > save ( ) ;
p - > translate ( itemGeometry . left ( ) , itemGeometry . top ( ) ) ;
2019-07-13 05:57:59 +00:00
// draw the page outline (black border and bottom-right shadow)
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
if ( ! itemGeometry . contains ( contentsRect ) ) {
int itemWidth = itemGeometry . width ( ) ;
int itemHeight = itemGeometry . height ( ) ;
// draw simple outline
2019-07-09 19:57:05 +00:00
QPen pen ( Qt : : black ) ;
pen . setWidth ( 0 ) ;
p - > setPen ( pen ) ;
QRectF outline ( - 1.0 / dpr , - 1.0 / dpr , itemWidth + 1.0 / dpr , itemHeight + 1.0 / dpr ) ;
p - > drawRect ( outline ) ;
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
// draw bottom/right gradient
2019-07-13 05:57:59 +00:00
for ( int i = 1 ; i < = shadowWidth ; i + + ) {
pen . setColor ( interpolateColor ( double ( i ) / ( shadowWidth + 1 ) ) ) ;
p - > setPen ( pen ) ;
QPointF left ( ( i - 1 ) / dpr , itemHeight + i / dpr ) ;
QPointF up ( itemWidth + i / dpr , ( i - 1 ) / dpr ) ;
QPointF corner ( itemWidth + i / dpr , itemHeight + i / dpr ) ;
p - > drawLine ( left , corner ) ;
p - > drawLine ( up , corner ) ;
Make page boundary rendering more robust
Okular renders a simple 'shadow' at the right and the bottom of each
page. The code for this is a bit fragile: After the page is rendered,
Okular paints a black outline, and then the shadow. The shadow is
a hand-implemented gradient, painted line by line. Finally, the
remaining area is painted in the background color. No pixel is
ever touched twice. Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in
https://bugs.kde.org/show_bug.cgi?id=383943
Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page. Finally,
the black outline and shadow are drawn on the previously drawn
background. This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.
BUG: 383943
2019-06-29 19:53:17 +00:00
}
}
p - > restore ( ) ;
}
2004-10-30 20:54:48 +00:00
}
void PageView : : updateItemSize ( PageViewItem * item , int colWidth , int rowHeight )
{
2006-09-21 08:45:36 +00:00
const Okular : : Page * okularPage = item - > page ( ) ;
double width = okularPage - > width ( ) , height = okularPage - > height ( ) , zoom = d - > zoomFactor ;
2008-05-19 00:37:14 +00:00
Okular : : NormalizedRect crop ( 0. , 0. , 1. , 1. ) ;
2015-08-27 20:09:02 +00:00
// Handle cropping, due to either "Trim Margin" or "Trim to Selection" cases
if ( ( Okular : : Settings : : trimMargins ( ) & & okularPage - > isBoundingBoxKnown ( ) & & ! okularPage - > boundingBox ( ) . isNull ( ) ) | | ( d - > aTrimToSelection & & d - > aTrimToSelection - > isChecked ( ) & & ! d - > trimBoundingBox . isNull ( ) ) ) {
crop = Okular : : Settings : : trimMargins ( ) ? okularPage - > boundingBox ( ) : d - > trimBoundingBox ;
2008-05-19 00:37:14 +00:00
2009-10-22 20:51:18 +00:00
// Rotate the bounding box
for ( int i = okularPage - > rotation ( ) ; i > 0 ; - - i ) {
2008-05-19 00:37:14 +00:00
Okular : : NormalizedRect rot = crop ;
crop . left = 1 - rot . bottom ;
crop . top = rot . left ;
crop . right = 1 - rot . top ;
crop . bottom = rot . right ;
}
2015-08-27 20:09:02 +00:00
// Expand the crop slightly beyond the bounding box (for Trim Margins only)
if ( Okular : : Settings : : trimMargins ( ) ) {
static const double cropExpandRatio = 0.04 ;
const double cropExpand = cropExpandRatio * ( ( crop . right - crop . left ) + ( crop . bottom - crop . top ) ) / 2 ;
crop = Okular : : NormalizedRect ( crop . left - cropExpand , crop . top - cropExpand , crop . right + cropExpand , crop . bottom + cropExpand ) & Okular : : NormalizedRect ( 0 , 0 , 1 , 1 ) ;
}
2008-05-19 00:37:14 +00:00
// We currently generate a larger image and then crop it, so if the
// crop rect is very small the generated image is huge. Hence, we shouldn't
// let the crop rect become too small.
2015-08-27 20:09:02 +00:00
static double minCropRatio ;
if ( Okular : : Settings : : trimMargins ( ) ) {
// Make sure we crop by at most 50% in either dimension:
minCropRatio = 0.5 ;
} else {
// Looser Constraint for "Trim Selection"
minCropRatio = 0.20 ;
}
2008-05-19 00:37:14 +00:00
if ( ( crop . right - crop . left ) < minCropRatio ) {
2013-08-18 15:19:20 +00:00
const double newLeft = ( crop . left + crop . right ) / 2 - minCropRatio / 2 ;
2008-05-19 00:37:14 +00:00
crop . left = qMax ( 0.0 , qMin ( 1.0 - minCropRatio , newLeft ) ) ;
crop . right = crop . left + minCropRatio ;
}
if ( ( crop . bottom - crop . top ) < minCropRatio ) {
2013-08-18 15:19:20 +00:00
const double newTop = ( crop . top + crop . bottom ) / 2 - minCropRatio / 2 ;
2008-05-19 00:37:14 +00:00
crop . top = qMax ( 0.0 , qMin ( 1.0 - minCropRatio , newTop ) ) ;
crop . bottom = crop . top + minCropRatio ;
}
width * = ( crop . right - crop . left ) ;
height * = ( crop . bottom - crop . top ) ;
# ifdef PAGEVIEW_DEBUG
qCDebug ( OkularUiDebug ) < < " Cropped page " < < okularPage - > number ( ) < < " to " < < crop < < " width " < < width < < " height " < < height < < " by bbox " < < okularPage - > boundingBox ( ) ;
# endif
}
2004-10-30 20:54:48 +00:00
if ( d - > zoomMode = = ZoomFixed ) {
width * = zoom ;
height * = zoom ;
2008-05-19 00:37:14 +00:00
item - > setWHZC ( ( int ) width , ( int ) height , d - > zoomFactor , crop ) ;
2004-10-30 20:54:48 +00:00
} else if ( d - > zoomMode = = ZoomFitWidth ) {
2008-05-19 00:37:14 +00:00
height = ( height / width ) * colWidth ;
zoom = ( double ) colWidth / width ;
item - > setWHZC ( colWidth , ( int ) height , zoom , crop ) ;
2014-08-24 20:37:15 +00:00
if ( ( uint ) item - > pageNumber ( ) = = d - > document - > currentPage ( ) )
d - > zoomFactor = zoom ;
2004-10-30 20:54:48 +00:00
} else if ( d - > zoomMode = = ZoomFitPage ) {
2013-08-18 15:19:20 +00:00
const double scaleW = ( double ) colWidth / ( double ) width ;
const double scaleH = ( double ) rowHeight / ( double ) height ;
2006-03-29 17:16:46 +00:00
zoom = qMin ( scaleW , scaleH ) ;
2008-05-19 00:37:14 +00:00
item - > setWHZC ( ( int ) ( zoom * width ) , ( int ) ( zoom * height ) , zoom , crop ) ;
2014-08-24 20:37:15 +00:00
if ( ( uint ) item - > pageNumber ( ) = = d - > document - > currentPage ( ) )
d - > zoomFactor = zoom ;
2013-08-18 15:19:20 +00:00
} else if ( d - > zoomMode = = ZoomFitAuto ) {
const double aspectRatioRelation = 1.25 ; // relation between aspect ratios for "auto fit"
const double uiAspect = ( double ) rowHeight / ( double ) colWidth ;
const double pageAspect = ( double ) height / ( double ) width ;
const double rel = uiAspect / pageAspect ;
const bool isContinuous = Okular : : Settings : : viewContinuous ( ) ;
if ( ! isContinuous & & rel > aspectRatioRelation ) {
// UI space is relatively much higher than the page
zoom = ( double ) rowHeight / ( double ) height ;
} else if ( rel < 1.0 / aspectRatioRelation ) {
// UI space is relatively much wider than the page in relation
zoom = ( double ) colWidth / ( double ) width ;
} else {
// aspect ratios of page and UI space are very similar
const double scaleW = ( double ) colWidth / ( double ) width ;
const double scaleH = ( double ) rowHeight / ( double ) height ;
zoom = qMin ( scaleW , scaleH ) ;
}
item - > setWHZC ( ( int ) ( zoom * width ) , ( int ) ( zoom * height ) , zoom , crop ) ;
2014-08-24 20:37:15 +00:00
if ( ( uint ) item - > pageNumber ( ) = = d - > document - > currentPage ( ) )
d - > zoomFactor = zoom ;
2013-08-18 15:19:20 +00:00
}
2004-10-30 20:54:48 +00:00
# ifndef NDEBUG
else
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) < < " calling updateItemSize with unrecognized d->zoomMode! " ;
2004-10-30 20:54:48 +00:00
# endif
}
PageViewItem * PageView : : pickItemOnPoint ( int x , int y )
{
2017-09-05 21:27:18 +00:00
PageViewItem * item = nullptr ;
2019-03-26 22:37:30 +00:00
for ( PageViewItem * i : qAsConst ( d - > visibleItems ) ) {
2008-05-19 00:37:14 +00:00
const QRect & r = i - > croppedGeometry ( ) ;
2004-10-30 20:54:48 +00:00
if ( x < r . right ( ) & & x > r . left ( ) & & y < r . bottom ( ) ) {
if ( y > r . top ( ) )
item = i ;
break ;
}
}
return item ;
}
2006-09-26 22:22:01 +00:00
void PageView : : textSelectionClear ( )
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
{
2006-09-26 22:22:01 +00:00
// something to clear
if ( ! d - > pagesWithTextSelection . isEmpty ( ) ) {
2019-03-26 22:37:30 +00:00
for ( const int page : qAsConst ( d - > pagesWithTextSelection ) )
d - > document - > setPageTextSelection ( page , nullptr , QColor ( ) ) ;
2006-09-26 22:22:01 +00:00
d - > pagesWithTextSelection . clear ( ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
}
2006-09-26 22:22:01 +00:00
}
2020-02-20 17:45:46 +00:00
void PageView : : selectionStart ( const QPoint pos , const QColor & color , bool /*aboveAll*/ )
2006-09-26 22:22:01 +00:00
{
selectionClear ( ) ;
d - > mouseSelecting = true ;
d - > mouseSelectionRect . setRect ( pos . x ( ) , pos . y ( ) , 1 , 1 ) ;
d - > mouseSelectionColor = color ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
// ensures page doesn't scroll
if ( d - > autoScrollTimer ) {
d - > scrollIncrement = 0 ;
d - > autoScrollTimer - > stop ( ) ;
}
}
2006-09-26 22:22:01 +00:00
2020-02-20 17:45:46 +00:00
void PageView : : scrollPosIntoView ( const QPoint pos )
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
{
Make selection scrolling go at 60 fps
Summary:
When you select a square with the right mouse button, and you go past the margin of the window (but where there is still space to go), okular scrolls the document so you can select more.
With this patch this automatic scrolling goes at 60 fps instead of 10, I made it so that the speed of the scroll is the same
Reviewers: #okular, aacid, sander, ngraham
Reviewed By: sander, ngraham
Subscribers: sander, ngraham, aacid, ahmedbilal, okular-devel, kezik
Tags: #okular
Differential Revision: https://phabricator.kde.org/D20437
2019-05-21 21:03:24 +00:00
// this number slows the speed of the page by its value, chosen not to be too fast or too slow, the actual speed is determined from the mouse position, not critical
const int damping = 6 ;
if ( pos . x ( ) < horizontalScrollBar ( ) - > value ( ) )
d - > dragScrollVector . setX ( ( pos . x ( ) - horizontalScrollBar ( ) - > value ( ) ) / damping ) ;
else if ( horizontalScrollBar ( ) - > value ( ) + viewport ( ) - > width ( ) < pos . x ( ) )
d - > dragScrollVector . setX ( ( pos . x ( ) - horizontalScrollBar ( ) - > value ( ) - viewport ( ) - > width ( ) ) / damping ) ;
2006-11-22 21:32:21 +00:00
else
d - > dragScrollVector . setX ( 0 ) ;
Make selection scrolling go at 60 fps
Summary:
When you select a square with the right mouse button, and you go past the margin of the window (but where there is still space to go), okular scrolls the document so you can select more.
With this patch this automatic scrolling goes at 60 fps instead of 10, I made it so that the speed of the scroll is the same
Reviewers: #okular, aacid, sander, ngraham
Reviewed By: sander, ngraham
Subscribers: sander, ngraham, aacid, ahmedbilal, okular-devel, kezik
Tags: #okular
Differential Revision: https://phabricator.kde.org/D20437
2019-05-21 21:03:24 +00:00
if ( pos . y ( ) < verticalScrollBar ( ) - > value ( ) )
d - > dragScrollVector . setY ( ( pos . y ( ) - verticalScrollBar ( ) - > value ( ) ) / damping ) ;
else if ( verticalScrollBar ( ) - > value ( ) + viewport ( ) - > height ( ) < pos . y ( ) )
d - > dragScrollVector . setY ( ( pos . y ( ) - verticalScrollBar ( ) - > value ( ) - viewport ( ) - > height ( ) ) / damping ) ;
2006-11-22 21:32:21 +00:00
else
d - > dragScrollVector . setY ( 0 ) ;
if ( d - > dragScrollVector ! = QPoint ( 0 , 0 ) ) {
Make selection scrolling go at 60 fps
Summary:
When you select a square with the right mouse button, and you go past the margin of the window (but where there is still space to go), okular scrolls the document so you can select more.
With this patch this automatic scrolling goes at 60 fps instead of 10, I made it so that the speed of the scroll is the same
Reviewers: #okular, aacid, sander, ngraham
Reviewed By: sander, ngraham
Subscribers: sander, ngraham, aacid, ahmedbilal, okular-devel, kezik
Tags: #okular
Differential Revision: https://phabricator.kde.org/D20437
2019-05-21 21:03:24 +00:00
if ( ! d - > dragScrollTimer . isActive ( ) )
d - > dragScrollTimer . start ( 1000 / 60 ) ; // 60 fps
2006-11-22 21:32:21 +00:00
} else
d - > dragScrollTimer . stop ( ) ;
2012-09-28 15:57:03 +00:00
}
2006-11-22 21:32:21 +00:00
Fix inconsistent viewport positioning in PageView
Summary:
This diff unifies the calculation of the viewport position from a given DocumentViewport. PageView::notifyViewportChanged and PageView::slotRelayoutPages used to handle it differntly, which resulted in viewport jumps for no reason.
It happened in various situations, e.g. when jumping to a page using the footer page navigation, or when reloading the document after presentation mode left, or when resizing the main window after presentation mode left.
The diff selects the notifyViewportChanged way (align viewport top border with page top margin) as golden behavior in case of rePos.enabled == false.
BUGS: 357958
CCBUG: 341939
CCBUG: 400890
341939 and 400890 are fixed partially. These two still suffer from a minor displacement that happens when finished signal arrives from pixmap generation thread.
Test Plan:
- When using the footer page navigation to jump to different pages, new page top is always algined with viewport top.
- After changing page with footer page navigation, press F5 to reload. Page top stays aligned with viewport top.
- When exiting presentation mode, and touching the file, page top stays aligned with viewport top.
- When exiting presentation mode, and changing main window size, page top stays aligned with viewport top.
Reviewers: #okular, sander
Reviewed By: sander
Subscribers: ngraham, sander, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16941
2018-11-22 17:50:14 +00:00
QPoint PageView : : viewportToContentArea ( const Okular : : DocumentViewport & vp ) const
{
Q_ASSERT ( vp . pageNumber > = 0 ) ;
const QRect & r = d - > items [ vp . pageNumber ] - > croppedGeometry ( ) ;
QPoint c { r . left ( ) , r . top ( ) } ;
if ( vp . rePos . enabled ) {
if ( vp . rePos . pos = = Okular : : DocumentViewport : : Center ) {
c . rx ( ) + = qRound ( normClamp ( vp . rePos . normalizedX , 0.5 ) * ( double ) r . width ( ) ) ;
c . ry ( ) + = qRound ( normClamp ( vp . rePos . normalizedY , 0.0 ) * ( double ) r . height ( ) ) ;
} else {
// TopLeft
2019-12-23 13:57:50 +00:00
c . rx ( ) + = qRound ( normClamp ( vp . rePos . normalizedX , 0.0 ) * ( double ) r . width ( ) + viewport ( ) - > width ( ) / 2.0 ) ;
c . ry ( ) + = qRound ( normClamp ( vp . rePos . normalizedY , 0.0 ) * ( double ) r . height ( ) + viewport ( ) - > height ( ) / 2.0 ) ;
Fix inconsistent viewport positioning in PageView
Summary:
This diff unifies the calculation of the viewport position from a given DocumentViewport. PageView::notifyViewportChanged and PageView::slotRelayoutPages used to handle it differntly, which resulted in viewport jumps for no reason.
It happened in various situations, e.g. when jumping to a page using the footer page navigation, or when reloading the document after presentation mode left, or when resizing the main window after presentation mode left.
The diff selects the notifyViewportChanged way (align viewport top border with page top margin) as golden behavior in case of rePos.enabled == false.
BUGS: 357958
CCBUG: 341939
CCBUG: 400890
341939 and 400890 are fixed partially. These two still suffer from a minor displacement that happens when finished signal arrives from pixmap generation thread.
Test Plan:
- When using the footer page navigation to jump to different pages, new page top is always algined with viewport top.
- After changing page with footer page navigation, press F5 to reload. Page top stays aligned with viewport top.
- When exiting presentation mode, and touching the file, page top stays aligned with viewport top.
- When exiting presentation mode, and changing main window size, page top stays aligned with viewport top.
Reviewers: #okular, sander
Reviewed By: sander
Subscribers: ngraham, sander, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16941
2018-11-22 17:50:14 +00:00
}
} else {
// exact repositioning disabled, align page top margin with viewport top border by default
c . rx ( ) + = r . width ( ) / 2 ;
c . ry ( ) + = viewport ( ) - > height ( ) / 2 - 10 ;
}
return c ;
}
2020-02-20 17:45:46 +00:00
void PageView : : updateSelection ( const QPoint pos )
2012-09-28 15:57:03 +00:00
{
if ( d - > mouseSelecting ) {
scrollPosIntoView ( pos ) ;
// update the selection rect
QRect updateRect = d - > mouseSelectionRect ;
d - > mouseSelectionRect . setBottomLeft ( pos ) ;
updateRect | = d - > mouseSelectionRect ;
updateRect . translate ( - contentAreaPosition ( ) ) ;
2017-02-08 22:16:50 +00:00
viewport ( ) - > update ( updateRect . adjusted ( - 1 , - 2 , 2 , 1 ) ) ;
2012-09-28 15:57:03 +00:00
} else if ( d - > mouseTextSelecting ) {
scrollPosIntoView ( pos ) ;
int first = - 1 ;
const QList < Okular : : RegularAreaRect * > selections = textSelections ( pos , d - > mouseSelectPos , first ) ;
QSet < int > pagesWithSelectionSet ;
for ( int i = 0 ; i < selections . count ( ) ; + + i )
pagesWithSelectionSet . insert ( i + first ) ;
const QSet < int > noMoreSelectedPages = d - > pagesWithTextSelection - pagesWithSelectionSet ;
// clear the selection from pages not selected anymore
2019-12-09 13:39:47 +00:00
for ( int p : noMoreSelectedPages ) {
2017-09-05 21:27:18 +00:00
d - > document - > setPageTextSelection ( p , nullptr , QColor ( ) ) ;
2012-09-28 15:57:03 +00:00
}
// set the new selection for the selected pages
2019-12-09 13:39:47 +00:00
for ( int p : qAsConst ( pagesWithSelectionSet ) ) {
2012-09-28 15:57:03 +00:00
d - > document - > setPageTextSelection ( p , selections [ p - first ] , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) ) ;
}
d - > pagesWithTextSelection = pagesWithSelectionSet ;
}
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
}
2020-02-20 17:45:46 +00:00
static Okular : : NormalizedPoint rotateInNormRect ( const QPoint rotated , const QRect rect , Okular : : Rotation rotation )
2007-09-03 19:35:55 +00:00
{
Okular : : NormalizedPoint ret ;
switch ( rotation ) {
case Okular : : Rotation0 :
ret = Okular : : NormalizedPoint ( rotated . x ( ) , rotated . y ( ) , rect . width ( ) , rect . height ( ) ) ;
break ;
case Okular : : Rotation90 :
ret = Okular : : NormalizedPoint ( rotated . y ( ) , rect . width ( ) - rotated . x ( ) , rect . height ( ) , rect . width ( ) ) ;
break ;
case Okular : : Rotation180 :
ret = Okular : : NormalizedPoint ( rect . width ( ) - rotated . x ( ) , rect . height ( ) - rotated . y ( ) , rect . width ( ) , rect . height ( ) ) ;
break ;
case Okular : : Rotation270 :
ret = Okular : : NormalizedPoint ( rect . height ( ) - rotated . y ( ) , rotated . x ( ) , rect . height ( ) , rect . width ( ) ) ;
break ;
}
return ret ;
}
2020-02-20 17:45:46 +00:00
Okular : : RegularAreaRect * PageView : : textSelectionForItem ( const PageViewItem * item , const QPoint startPoint , const QPoint endPoint )
2004-09-26 23:39:39 +00:00
{
2008-05-19 00:37:14 +00:00
const QRect & geometry = item - > uncroppedGeometry ( ) ;
2006-09-26 22:22:01 +00:00
Okular : : NormalizedPoint startCursor ( 0.0 , 0.0 ) ;
if ( ! startPoint . isNull ( ) ) {
2007-09-03 19:35:55 +00:00
startCursor = rotateInNormRect ( startPoint , geometry , item - > page ( ) - > rotation ( ) ) ;
2004-10-29 21:52:06 +00:00
}
2006-09-26 22:22:01 +00:00
Okular : : NormalizedPoint endCursor ( 1.0 , 1.0 ) ;
if ( ! endPoint . isNull ( ) ) {
2007-09-03 19:35:55 +00:00
endCursor = rotateInNormRect ( endPoint , geometry , item - > page ( ) - > rotation ( ) ) ;
2006-09-26 22:22:01 +00:00
}
Okular : : TextSelection mouseTextSelectionInfo ( startCursor , endCursor ) ;
2004-09-26 23:39:39 +00:00
2006-09-26 22:22:01 +00:00
const Okular : : Page * okularPage = item - > page ( ) ;
2006-11-23 16:09:26 +00:00
if ( ! okularPage - > hasTextPage ( ) )
2006-09-26 22:22:01 +00:00
d - > document - > requestTextPage ( okularPage - > number ( ) ) ;
2006-11-23 17:11:04 +00:00
Okular : : RegularAreaRect * selectionArea = okularPage - > textArea ( & mouseTextSelectionInfo ) ;
2006-12-23 16:36:08 +00:00
# ifdef PAGEVIEW_DEBUG
2014-09-11 17:36:01 +00:00
qCDebug ( OkularUiDebug ) . nospace ( ) < < " text areas ( " < < okularPage - > number ( ) < < " ): " < < ( selectionArea ? QString : : number ( selectionArea - > count ( ) ) : " (none) " ) ;
2006-12-23 16:36:08 +00:00
# endif
2006-10-03 17:13:42 +00:00
return selectionArea ;
2004-11-03 17:35:48 +00:00
}
2011-10-31 15:33:03 +00:00
void PageView : : selectionClear ( const ClearMode mode )
2004-11-03 17:35:48 +00:00
{
2017-02-08 22:16:50 +00:00
QRect updatedRect = d - > mouseSelectionRect . normalized ( ) . adjusted ( - 2 , - 2 , 2 , 2 ) ;
2005-06-24 16:41:55 +00:00
d - > mouseSelecting = false ;
2006-06-11 23:38:12 +00:00
d - > mouseSelectionRect . setCoords ( 0 , 0 , 0 , 0 ) ;
2011-10-12 13:50:56 +00:00
d - > tableSelectionCols . clear ( ) ;
d - > tableSelectionRows . clear ( ) ;
2011-10-31 15:33:03 +00:00
d - > tableDividersGuessed = false ;
2019-12-09 13:39:47 +00:00
for ( const TableSelectionPart & tsp : qAsConst ( d - > tableSelectionParts ) ) {
2011-10-12 13:50:56 +00:00
QRect selectionPartRect = tsp . rectInItem . geometry ( tsp . item - > uncroppedWidth ( ) , tsp . item - > uncroppedHeight ( ) ) ;
selectionPartRect . translate ( tsp . item - > uncroppedGeometry ( ) . topLeft ( ) ) ;
// should check whether this is on-screen here?
updatedRect = updatedRect . united ( selectionPartRect ) ;
}
2011-10-31 15:33:03 +00:00
if ( mode ! = ClearOnlyDividers ) {
d - > tableSelectionParts . clear ( ) ;
}
2011-10-12 13:50:56 +00:00
d - > tableSelectionParts . clear ( ) ;
updatedRect . translate ( - contentAreaPosition ( ) ) ;
2009-06-29 20:55:50 +00:00
viewport ( ) - > update ( updatedRect ) ;
2004-11-03 17:35:48 +00:00
}
2014-05-05 22:43:40 +00:00
// const to be used for both zoomFactorFitMode function and slotRelayoutPages.
static const int kcolWidthMargin = 6 ;
static const int krowHeightMargin = 12 ;
double PageView : : zoomFactorFitMode ( ZoomMode mode )
{
const int pageCount = d - > items . count ( ) ;
if ( pageCount = = 0 )
return 0 ;
const bool facingCentered = Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : FacingFirstCentered | | ( Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : Facing & & pageCount = = 1 ) ;
const bool overrideCentering = facingCentered & & pageCount < 3 ;
const int nCols = overrideCentering ? 1 : viewColumns ( ) ;
2020-05-25 22:20:54 +00:00
const int colWidth = viewport ( ) - > width ( ) / nCols - kcolWidthMargin ;
2014-05-05 22:43:40 +00:00
const double rowHeight = viewport ( ) - > height ( ) - krowHeightMargin ;
const PageViewItem * currentItem = d - > items [ qMax ( 0 , ( int ) d - > document - > currentPage ( ) ) ] ;
2018-11-14 19:12:15 +00:00
// prevent segmentation fault when opening a new document;
2014-05-05 22:43:40 +00:00
if ( ! currentItem )
return 0 ;
const Okular : : Page * okularPage = currentItem - > page ( ) ;
const double width = okularPage - > width ( ) , height = okularPage - > height ( ) ;
if ( mode = = ZoomFitWidth )
return ( double ) colWidth / width ;
if ( mode = = ZoomFitPage ) {
const double scaleW = ( double ) colWidth / ( double ) width ;
const double scaleH = ( double ) rowHeight / ( double ) height ;
return qMin ( scaleW , scaleH ) ;
}
return 0 ;
}
2004-11-03 17:35:48 +00:00
void PageView : : updateZoom ( ZoomMode newZoomMode )
{
2004-10-29 21:52:06 +00:00
if ( newZoomMode = = ZoomFixed ) {
if ( d - > aZoom - > currentItem ( ) = = 0 )
newZoomMode = ZoomFitWidth ;
else if ( d - > aZoom - > currentItem ( ) = = 1 )
newZoomMode = ZoomFitPage ;
2013-08-18 15:19:20 +00:00
else if ( d - > aZoom - > currentItem ( ) = = 2 )
newZoomMode = ZoomFitAuto ;
2004-10-29 21:52:06 +00:00
}
2004-09-26 23:39:39 +00:00
2004-10-29 21:52:06 +00:00
float newFactor = d - > zoomFactor ;
2017-09-05 21:27:18 +00:00
QAction * checkedZoomAction = nullptr ;
2004-10-29 21:52:06 +00:00
switch ( newZoomMode ) {
2004-11-03 17:35:48 +00:00
case ZoomFixed : { // ZoomFixed case
2004-10-29 21:52:06 +00:00
QString z = d - > aZoom - > currentText ( ) ;
2006-07-29 12:52:35 +00:00
// kdelibs4 sometimes adds accelerators to actions' text directly :(
2016-07-11 20:05:18 +00:00
z . remove ( QLatin1Char ( ' & ' ) ) ;
z . remove ( QLatin1Char ( ' % ' ) ) ;
2015-01-29 20:48:47 +00:00
newFactor = QLocale ( ) . toDouble ( z ) / 100.0 ;
2004-10-29 21:52:06 +00:00
} break ;
case ZoomIn :
2014-05-05 22:43:40 +00:00
case ZoomOut : {
const float zoomFactorFitWidth = zoomFactorFitMode ( ZoomFitWidth ) ;
const float zoomFactorFitPage = zoomFactorFitMode ( ZoomFitPage ) ;
2020-07-10 22:15:05 +00:00
2020-03-08 16:26:49 +00:00
QVector < float > zoomValue ( kZoomValues . size ( ) ) ;
2020-07-10 22:15:05 +00:00
2019-03-12 12:13:53 +00:00
std : : copy ( kZoomValues . begin ( ) , kZoomValues . end ( ) , zoomValue . begin ( ) ) ;
2014-08-21 21:34:54 +00:00
zoomValue . append ( zoomFactorFitWidth ) ;
2019-07-23 15:30:44 +00:00
zoomValue . append ( zoomFactorFitPage ) ;
std : : sort ( zoomValue . begin ( ) , zoomValue . end ( ) ) ;
2020-07-10 22:15:05 +00:00
2019-07-23 15:30:44 +00:00
QVector < float > : : iterator i ;
2014-05-05 22:43:40 +00:00
if ( newZoomMode = = ZoomOut ) {
2014-08-21 21:34:54 +00:00
if ( newFactor < = zoomValue . first ( ) )
return ;
2019-07-23 15:30:44 +00:00
i = std : : lower_bound ( zoomValue . begin ( ) , zoomValue . end ( ) , newFactor ) - 1 ;
2014-05-05 22:43:40 +00:00
} else {
if ( newFactor > = zoomValue . last ( ) )
2020-07-10 22:15:05 +00:00
return ;
2014-05-05 22:43:40 +00:00
i = std : : upper_bound ( zoomValue . begin ( ) , zoomValue . end ( ) , newFactor ) ;
2020-07-10 22:15:05 +00:00
}
2014-05-05 22:43:40 +00:00
const float tmpFactor = * i ;
if ( tmpFactor = = zoomFactorFitWidth ) {
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
newZoomMode = ZoomFitWidth ;
2004-10-29 21:52:06 +00:00
checkedZoomAction = d - > aZoomFitWidth ;
} else if ( tmpFactor = = zoomFactorFitPage ) {
newZoomMode = ZoomFitPage ;
checkedZoomAction = d - > aZoomFitPage ;
2013-08-18 15:19:20 +00:00
} else {
newFactor = tmpFactor ;
2004-10-29 21:52:06 +00:00
newZoomMode = ZoomFixed ;
2020-07-10 22:15:05 +00:00
}
} break ;
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
case ZoomActual :
2014-05-05 22:43:40 +00:00
newZoomMode = ZoomFixed ;
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
newFactor = 1.0 ;
2020-07-10 22:15:05 +00:00
break ;
2004-10-29 21:52:06 +00:00
case ZoomFitWidth :
2014-05-05 22:43:40 +00:00
checkedZoomAction = d - > aZoomFitWidth ;
2020-07-10 22:15:05 +00:00
break ;
2014-05-05 22:43:40 +00:00
case ZoomFitPage :
2004-10-29 21:52:06 +00:00
checkedZoomAction = d - > aZoomFitPage ;
2020-07-10 22:15:05 +00:00
break ;
2013-08-18 15:19:20 +00:00
case ZoomFitAuto :
checkedZoomAction = d - > aZoomAutoFit ;
2020-07-10 22:15:05 +00:00
break ;
2004-10-29 21:52:06 +00:00
case ZoomRefreshCurrent :
2014-05-05 22:43:40 +00:00
newZoomMode = ZoomFixed ;
2004-10-29 21:52:06 +00:00
d - > zoomFactor = - 1 ;
break ;
}
2020-05-15 17:44:04 +00:00
const float upperZoomLimit = d - > document - > supportsTiles ( ) ? 100.0 : 4.0 ;
2012-11-15 22:18:59 +00:00
if ( newFactor > upperZoomLimit )
newFactor = upperZoomLimit ;
2004-10-30 23:59:09 +00:00
if ( newFactor < 0.1 )
newFactor = 0.1 ;
2004-09-26 23:39:39 +00:00
2004-10-29 21:52:06 +00:00
if ( newZoomMode ! = d - > zoomMode | | ( newZoomMode = = ZoomFixed & & newFactor ! = d - > zoomFactor ) ) {
2004-10-30 23:59:09 +00:00
// rebuild layout and update the whole viewport
2004-10-29 21:52:06 +00:00
d - > zoomMode = newZoomMode ;
d - > zoomFactor = newFactor ;
2005-01-09 23:37:07 +00:00
// be sure to block updates to document's viewport
bool prevState = d - > blockViewport ;
d - > blockViewport = true ;
2004-10-29 21:52:06 +00:00
slotRelayoutPages ( ) ;
2005-01-09 23:37:07 +00:00
d - > blockViewport = prevState ;
2004-10-30 23:59:09 +00:00
// request pixmaps
slotRequestVisiblePixmaps ( ) ;
// update zoom text
2004-10-29 21:52:06 +00:00
updateZoomText ( ) ;
// update actions checked state
2007-07-14 12:31:26 +00:00
if ( d - > aZoomFitWidth ) {
2010-07-26 22:22:59 +00:00
d - > aZoomFitWidth - > setChecked ( checkedZoomAction = = d - > aZoomFitWidth ) ;
d - > aZoomFitPage - > setChecked ( checkedZoomAction = = d - > aZoomFitPage ) ;
2013-08-18 15:19:20 +00:00
d - > aZoomAutoFit - > setChecked ( checkedZoomAction = = d - > aZoomAutoFit ) ;
2007-07-14 12:31:26 +00:00
}
2010-07-26 22:22:59 +00:00
} else if ( newZoomMode = = ZoomFixed & & newFactor = = d - > zoomFactor )
updateZoomText ( ) ;
2007-01-28 16:29:48 +00:00
2012-11-15 22:18:59 +00:00
d - > aZoomIn - > setEnabled ( d - > zoomFactor < upperZoomLimit - 0.001 ) ;
2012-06-16 17:57:30 +00:00
d - > aZoomOut - > setEnabled ( d - > zoomFactor > 0.101 ) ;
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
d - > aZoomActual - > setEnabled ( d - > zoomFactor ! = 1.0 ) ;
2004-09-26 23:39:39 +00:00
}
2004-10-29 21:52:06 +00:00
void PageView : : updateZoomText ( )
2004-09-26 23:39:39 +00:00
{
2004-10-29 21:52:06 +00:00
// use current page zoom as zoomFactor if in ZoomFit/* mode
2004-11-05 00:14:00 +00:00
if ( d - > zoomMode ! = ZoomFixed & & d - > items . count ( ) > 0 )
2006-03-29 17:16:46 +00:00
d - > zoomFactor = d - > items [ qMax ( 0 , ( int ) d - > document - > currentPage ( ) ) ] - > zoomFactor ( ) ;
2004-10-29 21:52:06 +00:00
float newFactor = d - > zoomFactor ;
2006-04-13 11:24:57 +00:00
d - > aZoom - > removeAllActions ( ) ;
2004-09-26 23:39:39 +00:00
2004-10-29 21:52:06 +00:00
// add items that describe fit actions
QStringList translated ;
2013-08-18 15:19:20 +00:00
translated < < i18n ( " Fit Width " ) < < i18n ( " Fit Page " ) < < i18n ( " Auto Fit " ) ;
2004-10-20 16:41:13 +00:00
2004-10-29 21:52:06 +00:00
// add percent items
2013-08-18 15:19:20 +00:00
int idx = 0 , selIdx = 3 ;
2004-10-29 21:52:06 +00:00
bool inserted = false ; // use: "d->zoomMode != ZoomFixed" to hide Fit/* zoom ratio
2012-12-01 00:34:54 +00:00
int zoomValueCount = 11 ;
2012-11-15 22:18:59 +00:00
if ( d - > document - > supportsTiles ( ) )
2020-05-15 17:44:04 +00:00
zoomValueCount = kZoomValues . size ( ) ;
2012-11-15 22:18:59 +00:00
while ( idx < zoomValueCount | | ! inserted ) {
2014-05-05 22:43:40 +00:00
float value = idx < zoomValueCount ? kZoomValues [ idx ] : newFactor ;
2004-10-29 21:52:06 +00:00
if ( ! inserted & & newFactor < ( value - 0.0001 ) )
value = newFactor ;
else
idx + + ;
if ( value > ( newFactor - 0.0001 ) & & value < ( newFactor + 0.0001 ) )
inserted = true ;
if ( ! inserted )
selIdx + + ;
2014-05-05 22:43:40 +00:00
// we do not need to display 2-digit precision
2015-02-24 22:24:44 +00:00
QString localValue ( QLocale ( ) . toString ( value * 100.0 , ' f ' , 1 ) ) ;
2016-07-11 20:05:18 +00:00
localValue . remove ( QLocale ( ) . decimalPoint ( ) + QLatin1Char ( ' 0 ' ) ) ;
2006-11-03 22:09:16 +00:00
// remove a trailing zero in numbers like 66.70
2015-01-29 20:48:47 +00:00
if ( localValue . right ( 1 ) = = QLatin1String ( " 0 " ) & & localValue . indexOf ( QLocale ( ) . decimalPoint ( ) ) > - 1 )
2006-11-03 22:09:16 +00:00
localValue . chop ( 1 ) ;
2015-10-29 12:37:11 +00:00
translated < < QStringLiteral ( " %1% " ) . arg ( localValue ) ;
2004-09-28 13:53:47 +00:00
}
2004-10-29 21:52:06 +00:00
d - > aZoom - > setItems ( translated ) ;
// select current item in list
if ( d - > zoomMode = = ZoomFitWidth )
selIdx = 0 ;
else if ( d - > zoomMode = = ZoomFitPage )
selIdx = 1 ;
2013-08-18 15:19:20 +00:00
else if ( d - > zoomMode = = ZoomFitAuto )
selIdx = 2 ;
2011-11-24 21:28:07 +00:00
// we have to temporarily enable the actions as otherwise we can't set a new current item
d - > aZoom - > setEnabled ( true ) ;
d - > aZoom - > selectableActionGroup ( ) - > setEnabled ( true ) ;
2004-10-29 21:52:06 +00:00
d - > aZoom - > setCurrentItem ( selIdx ) ;
2011-11-24 21:28:07 +00:00
d - > aZoom - > setEnabled ( d - > items . size ( ) > 0 ) ;
d - > aZoom - > selectableActionGroup ( ) - > setEnabled ( d - > items . size ( ) > 0 ) ;
2004-09-26 23:39:39 +00:00
}
2019-09-18 07:40:06 +00:00
void PageView : : updateViewMode ( const int nr )
{
2020-03-12 21:03:47 +00:00
const QList < QAction * > actions = d - > viewModeActionGroup - > actions ( ) ;
2020-02-19 16:28:08 +00:00
for ( QAction * action : actions ) {
2019-09-18 07:40:06 +00:00
QVariant mode_id = action - > data ( ) ;
if ( mode_id . toInt ( ) = = nr ) {
2019-09-18 07:48:42 +00:00
action - > trigger ( ) ;
2019-09-18 07:40:06 +00:00
}
}
}
2013-06-23 18:42:19 +00:00
void PageView : : updateCursor ( )
{
const QPoint p = contentAreaPosition ( ) + viewport ( ) - > mapFromGlobal ( QCursor : : pos ( ) ) ;
updateCursor ( p ) ;
}
2020-02-20 17:45:46 +00:00
void PageView : : updateCursor ( const QPoint p )
2004-12-26 21:20:17 +00:00
{
2017-09-21 20:16:31 +00:00
// reset mouse over link it will be re-set if that still valid
d - > mouseOverLinkObject = nullptr ;
2004-12-26 21:20:17 +00:00
// detect the underlaying page (if present)
PageViewItem * pageItem = pickItemOnPoint ( p . x ( ) , p . y ( ) ) ;
2020-10-21 00:40:01 +00:00
QScroller : : State scrollerState = d - > scroller - > state ( ) ;
2013-07-02 21:29:20 +00:00
if ( d - > annotator & & d - > annotator - > active ( ) ) {
if ( pageItem | | d - > annotator - > annotating ( ) )
2013-07-30 21:36:55 +00:00
setCursor ( d - > annotator - > cursor ( ) ) ;
2013-07-02 21:29:20 +00:00
else
setCursor ( Qt : : ForbiddenCursor ) ;
2020-10-21 00:40:01 +00:00
} else if ( scrollerState = = QScroller : : Pressed | | scrollerState = = QScroller : : Dragging ) {
setCursor ( Qt : : ClosedHandCursor ) ;
2013-07-02 21:29:20 +00:00
} else if ( pageItem ) {
2008-05-19 00:37:14 +00:00
double nX = pageItem - > absToPageX ( p . x ( ) ) ;
double nY = pageItem - > absToPageY ( p . y ( ) ) ;
2017-09-21 20:16:31 +00:00
Qt : : CursorShape cursorShapeFallback ;
2004-12-26 21:20:17 +00:00
2005-02-09 17:45:16 +00:00
// if over a ObjectRect (of type Link) change cursor to hand
2017-09-21 20:16:31 +00:00
switch ( d - > mouseMode ) {
case Okular : : Settings : : EnumMouseMode : : TextSelect :
if ( d - > mouseTextSelecting ) {
setCursor ( Qt : : IBeamCursor ) ;
return ;
}
cursorShapeFallback = Qt : : IBeamCursor ;
break ;
case Okular : : Settings : : EnumMouseMode : : Magnifier :
setCursor ( Qt : : CrossCursor ) ;
return ;
case Okular : : Settings : : EnumMouseMode : : RectSelect :
case Okular : : Settings : : EnumMouseMode : : TrimSelect :
if ( d - > mouseSelecting ) {
setCursor ( Qt : : CrossCursor ) ;
return ;
}
cursorShapeFallback = Qt : : CrossCursor ;
break ;
case Okular : : Settings : : EnumMouseMode : : Browse :
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
d - > mouseOnRect = false ;
if ( d - > mouseAnnotation - > isMouseOver ( ) ) {
2006-10-16 19:19:42 +00:00
d - > mouseOnRect = true ;
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
setCursor ( d - > mouseAnnotation - > cursor ( ) ) ;
2017-09-21 20:16:31 +00:00
return ;
2006-09-26 22:22:01 +00:00
} else {
2017-09-21 20:16:31 +00:00
cursorShapeFallback = Qt : : OpenHandCursor ;
2006-11-11 13:45:44 +00:00
}
2017-09-21 20:16:31 +00:00
break ;
default :
setCursor ( Qt : : ArrowCursor ) ;
return ;
}
const Okular : : ObjectRect * linkobj = pageItem - > page ( ) - > objectRect ( Okular : : ObjectRect : : Action , nX , nY , pageItem - > uncroppedWidth ( ) , pageItem - > uncroppedHeight ( ) ) ;
if ( linkobj ) {
d - > mouseOverLinkObject = linkobj ;
d - > mouseOnRect = true ;
setCursor ( Qt : : PointingHandCursor ) ;
2013-07-02 22:01:22 +00:00
} else {
2017-09-21 20:16:31 +00:00
setCursor ( cursorShapeFallback ) ;
2013-07-02 22:01:22 +00:00
}
2004-12-26 21:20:17 +00:00
} else {
// if there's no page over the cursor and we were showing the pointingHandCursor
// go back to the normal one
2005-01-02 11:50:38 +00:00
d - > mouseOnRect = false ;
2006-06-03 13:01:15 +00:00
setCursor ( Qt : : ArrowCursor ) ;
2004-12-26 21:20:17 +00:00
}
}
2015-07-20 16:55:35 +00:00
void PageView : : reloadForms ( )
{
if ( d - > m_formsVisible ) {
2019-03-26 22:37:30 +00:00
for ( PageViewItem * item : qAsConst ( d - > visibleItems ) ) {
item - > reloadFormWidgetsState ( ) ;
2015-07-20 16:55:35 +00:00
}
}
}
2020-02-20 17:45:46 +00:00
void PageView : : moveMagnifier ( const QPoint p ) // non scaled point
2014-02-24 22:42:10 +00:00
{
const int w = d - > magnifierView - > width ( ) * 0.5 ;
const int h = d - > magnifierView - > height ( ) * 0.5 ;
int x = p . x ( ) - w ;
int y = p . y ( ) - h ;
const int max_x = viewport ( ) - > width ( ) ;
const int max_y = viewport ( ) - > height ( ) ;
QPoint scroll ( 0 , 0 ) ;
if ( x < 0 ) {
if ( horizontalScrollBar ( ) - > value ( ) > 0 )
scroll . setX ( x - w ) ;
x = 0 ;
}
if ( y < 0 ) {
if ( verticalScrollBar ( ) - > value ( ) > 0 )
scroll . setY ( y - h ) ;
y = 0 ;
}
if ( p . x ( ) + w > max_x ) {
if ( horizontalScrollBar ( ) - > value ( ) < horizontalScrollBar ( ) - > maximum ( ) )
scroll . setX ( p . x ( ) + 2 * w - max_x ) ;
x = max_x - d - > magnifierView - > width ( ) - 1 ;
}
if ( p . y ( ) + h > max_y ) {
if ( verticalScrollBar ( ) - > value ( ) < verticalScrollBar ( ) - > maximum ( ) )
scroll . setY ( p . y ( ) + 2 * h - max_y ) ;
y = max_y - d - > magnifierView - > height ( ) - 1 ;
}
if ( ! scroll . isNull ( ) )
scrollPosIntoView ( contentAreaPoint ( p + scroll ) ) ;
d - > magnifierView - > move ( x , y ) ;
}
2020-02-20 17:45:46 +00:00
void PageView : : updateMagnifier ( const QPoint p ) // scaled point
2014-02-24 22:42:10 +00:00
{
/* translate mouse coordinates to page coordinates and inform the magnifier of the situation */
PageViewItem * item = pickItemOnPoint ( p . x ( ) , p . y ( ) ) ;
if ( item ) {
Okular : : NormalizedPoint np ( item - > absToPageX ( p . x ( ) ) , item - > absToPageY ( p . y ( ) ) ) ;
d - > magnifierView - > updateView ( np , item - > page ( ) ) ;
}
}
2006-10-16 19:47:20 +00:00
int PageView : : viewColumns ( ) const
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
{
2010-01-10 01:19:16 +00:00
int vm = Okular : : Settings : : viewMode ( ) ;
if ( vm = = Okular : : Settings : : EnumViewMode : : Single )
return 1 ;
else if ( vm = = Okular : : Settings : : EnumViewMode : : Facing | | vm = = Okular : : Settings : : EnumViewMode : : FacingFirstCentered )
return 2 ;
2018-05-18 12:52:40 +00:00
else if ( vm = = Okular : : Settings : : EnumViewMode : : Summary & & d - > document - > pages ( ) < Okular : : Settings : : viewColumns ( ) )
2017-10-28 12:45:09 +00:00
return d - > document - > pages ( ) ;
2010-01-10 01:19:16 +00:00
else
return Okular : : Settings : : viewColumns ( ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
}
2019-11-15 16:08:25 +00:00
void PageView : : center ( int cx , int cy , bool smoothMove )
2006-10-07 14:40:32 +00:00
{
2019-11-15 16:08:25 +00:00
scrollTo ( cx - viewport ( ) - > width ( ) / 2 , cy - viewport ( ) - > height ( ) / 2 , smoothMove ) ;
2012-09-03 00:55:16 +00:00
}
2019-11-15 16:08:25 +00:00
void PageView : : scrollTo ( int x , int y , bool smoothMove )
2012-09-03 00:55:16 +00:00
{
2020-11-08 12:14:22 +00:00
# if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
// Workaround for QTBUG-88288, (KDE bug 425188): To avoid a crash in QScroller,
// we need to make sure the target widget intersects a physical screen.
// QScroller queries QDesktopWidget::screenNumber().
// If we are not on a physical screen, we try to make our widget big enough.
// The geometry will be restored to a sensible value once the Part is shown.
// It should be enough to add this workaround ony in PageView::scrollTo(),
// because we don’ t expect other QScroller::scrollTo() calls before PageView is shown.
if ( QApplication : : desktop ( ) - > screenNumber ( this ) < 0 ) {
setGeometry ( QRect ( - 1000 , - 1000 , 5000 , 5000 ) . united ( QApplication : : desktop ( ) - > availableGeometry ( ) ) ) ;
}
# endif
2012-09-03 00:55:16 +00:00
bool prevState = d - > blockPixmapsRequest ;
2012-11-12 02:09:12 +00:00
2012-09-03 00:55:16 +00:00
int newValue = - 1 ;
2012-11-12 02:09:12 +00:00
if ( x ! = horizontalScrollBar ( ) - > value ( ) | | y ! = verticalScrollBar ( ) - > value ( ) )
newValue = 1 ; // Pretend this call is the result of a scrollbar event
2012-09-03 00:55:16 +00:00
d - > blockPixmapsRequest = true ;
2019-11-15 16:08:25 +00:00
if ( smoothMove )
2020-09-11 21:19:36 +00:00
d - > scroller - > scrollTo ( QPoint ( x , y ) , d - > currentLongScrollDuration ) ;
2019-11-15 16:08:25 +00:00
else
d - > scroller - > scrollTo ( QPoint ( x , y ) , 0 ) ;
2012-09-03 00:55:16 +00:00
d - > blockPixmapsRequest = prevState ;
slotRequestVisiblePixmaps ( newValue ) ;
2006-10-07 14:40:32 +00:00
}
2007-02-25 00:07:59 +00:00
void PageView : : toggleFormWidgets ( bool on )
{
2007-02-25 14:59:26 +00:00
bool somehadfocus = false ;
2019-03-26 22:37:30 +00:00
for ( PageViewItem * item : qAsConst ( d - > items ) ) {
const bool hadfocus = item - > setFormWidgetsVisible ( on ) ;
2007-10-18 20:35:34 +00:00
somehadfocus = somehadfocus | | hadfocus ;
2007-02-25 00:07:59 +00:00
}
2007-02-25 14:59:26 +00:00
if ( somehadfocus )
setFocus ( ) ;
2007-02-25 00:07:59 +00:00
d - > m_formsVisible = on ;
}
2020-02-20 17:45:46 +00:00
void PageView : : resizeContentArea ( const QSize newSize )
2009-06-29 20:55:50 +00:00
{
const QSize vs = viewport ( ) - > size ( ) ;
2015-03-16 23:20:11 +00:00
int hRange = newSize . width ( ) - vs . width ( ) ;
int vRange = newSize . height ( ) - vs . height ( ) ;
if ( horizontalScrollBar ( ) - > isVisible ( ) & & hRange = = verticalScrollBar ( ) - > width ( ) & & verticalScrollBar ( ) - > isVisible ( ) & & vRange = = horizontalScrollBar ( ) - > height ( ) & & Okular : : Settings : : showScrollBars ( ) ) {
hRange = 0 ;
vRange = 0 ;
}
horizontalScrollBar ( ) - > setRange ( 0 , hRange ) ;
verticalScrollBar ( ) - > setRange ( 0 , vRange ) ;
2011-09-07 22:43:30 +00:00
updatePageStep ( ) ;
}
void PageView : : updatePageStep ( )
{
const QSize vs = viewport ( ) - > size ( ) ;
horizontalScrollBar ( ) - > setPageStep ( vs . width ( ) ) ;
2011-09-07 22:46:03 +00:00
verticalScrollBar ( ) - > setPageStep ( vs . height ( ) * ( 100 - Okular : : Settings : : scrollOverlap ( ) ) / 100 ) ;
2009-06-29 20:55:50 +00:00
}
2014-08-13 10:45:40 +00:00
void PageView : : addWebShortcutsMenu ( QMenu * menu , const QString & text )
2010-09-11 13:34:22 +00:00
{
if ( text . isEmpty ( ) ) {
return ;
}
QString searchText = text ;
2016-07-24 20:12:26 +00:00
searchText = searchText . replace ( QLatin1Char ( ' \n ' ) , QLatin1Char ( ' ' ) ) . replace ( QLatin1Char ( ' \r ' ) , QLatin1Char ( ' ' ) ) . simplified ( ) ;
2010-09-11 13:34:22 +00:00
if ( searchText . isEmpty ( ) ) {
return ;
}
KUriFilterData filterData ( searchText ) ;
filterData . setSearchFilteringOptions ( KUriFilterData : : RetrievePreferredSearchProvidersOnly ) ;
if ( KUriFilter : : self ( ) - > filterSearchUri ( filterData , KUriFilter : : NormalTextFilter ) ) {
const QStringList searchProviders = filterData . preferredSearchProviders ( ) ;
if ( ! searchProviders . isEmpty ( ) ) {
2016-07-24 20:12:26 +00:00
QMenu * webShortcutsMenu = new QMenu ( menu ) ;
webShortcutsMenu - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " preferences-web-browser-shortcuts " ) ) ) ;
2010-09-11 13:34:22 +00:00
2019-08-25 10:19:43 +00:00
const QString squeezedText = KStringHandler : : rsqueeze ( searchText , searchTextPreviewLength ) ;
2010-09-11 13:34:22 +00:00
webShortcutsMenu - > setTitle ( i18n ( " Search for '%1' with " , squeezedText ) ) ;
2017-09-05 21:27:18 +00:00
QAction * action = nullptr ;
2010-09-11 13:34:22 +00:00
2019-12-09 13:39:47 +00:00
for ( const QString & searchProvider : searchProviders ) {
2016-07-24 20:12:26 +00:00
action = new QAction ( searchProvider , webShortcutsMenu ) ;
action - > setIcon ( QIcon : : fromTheme ( filterData . iconNameForPreferredSearchProvider ( searchProvider ) ) ) ;
2010-09-11 13:34:22 +00:00
action - > setData ( filterData . queryForPreferredSearchProvider ( searchProvider ) ) ;
2016-07-24 20:12:26 +00:00
connect ( action , & QAction : : triggered , this , & PageView : : slotHandleWebShortcutAction ) ;
2010-09-11 13:34:22 +00:00
webShortcutsMenu - > addAction ( action ) ;
}
webShortcutsMenu - > addSeparator ( ) ;
2016-07-24 20:12:26 +00:00
action = new QAction ( i18n ( " Configure Web Shortcuts... " ) , webShortcutsMenu ) ;
action - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " configure " ) ) ) ;
connect ( action , & QAction : : triggered , this , & PageView : : slotConfigureWebShortcuts ) ;
2010-09-11 13:34:22 +00:00
webShortcutsMenu - > addAction ( action ) ;
menu - > addMenu ( webShortcutsMenu ) ;
}
}
}
2020-02-20 17:45:46 +00:00
QMenu * PageView : : createProcessLinkMenu ( PageViewItem * item , const QPoint eventPos )
2017-09-21 20:16:31 +00:00
{
// check if the right-click was over a link
const double nX = item - > absToPageX ( eventPos . x ( ) ) ;
const double nY = item - > absToPageY ( eventPos . y ( ) ) ;
const Okular : : ObjectRect * rect = item - > page ( ) - > objectRect ( Okular : : ObjectRect : : Action , nX , nY , item - > uncroppedWidth ( ) , item - > uncroppedHeight ( ) ) ;
if ( rect ) {
const Okular : : Action * link = static_cast < const Okular : : Action * > ( rect - > object ( ) ) ;
2019-06-22 10:35:17 +00:00
if ( ! link )
return nullptr ;
QMenu * menu = new QMenu ( this ) ;
2017-09-21 20:16:31 +00:00
// creating the menu and its actions
QAction * processLink = menu - > addAction ( i18n ( " Follow This Link " ) ) ;
2019-04-25 21:10:48 +00:00
processLink - > setObjectName ( QStringLiteral ( " ProcessLinkAction " ) ) ;
2017-09-21 20:16:31 +00:00
if ( link - > actionType ( ) = = Okular : : Action : : Sound ) {
processLink - > setText ( i18n ( " Play this Sound " ) ) ;
if ( Okular : : AudioPlayer : : instance ( ) - > state ( ) = = Okular : : AudioPlayer : : PlayingState ) {
QAction * actStopSound = menu - > addAction ( i18n ( " Stop Sound " ) ) ;
connect ( actStopSound , & QAction : : triggered , [ ] ( ) { Okular : : AudioPlayer : : instance ( ) - > stopPlaybacks ( ) ; } ) ;
}
}
if ( dynamic_cast < const Okular : : BrowseAction * > ( link ) ) {
QAction * actCopyLinkLocation = menu - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-copy " ) ) , i18n ( " Copy Link Address " ) ) ;
2019-04-25 21:10:48 +00:00
actCopyLinkLocation - > setObjectName ( QStringLiteral ( " CopyLinkLocationAction " ) ) ;
2020-02-20 11:42:34 +00:00
connect ( actCopyLinkLocation , & QAction : : triggered , menu , [ link ] ( ) {
2017-09-21 20:16:31 +00:00
const Okular : : BrowseAction * browseLink = static_cast < const Okular : : BrowseAction * > ( link ) ;
QClipboard * cb = QApplication : : clipboard ( ) ;
cb - > setText ( browseLink - > url ( ) . toDisplayString ( ) , QClipboard : : Clipboard ) ;
if ( cb - > supportsSelection ( ) )
cb - > setText ( browseLink - > url ( ) . toDisplayString ( ) , QClipboard : : Selection ) ;
} ) ;
}
2020-02-20 11:42:34 +00:00
connect ( processLink , & QAction : : triggered , this , [ this , link ] ( ) { d - > document - > processAction ( link ) ; } ) ;
2017-09-21 20:16:31 +00:00
return menu ;
}
return nullptr ;
}
2019-08-25 10:19:43 +00:00
void PageView : : addSearchWithinDocumentAction ( QMenu * menu , const QString & searchText )
{
const QString squeezedText = KStringHandler : : rsqueeze ( searchText , searchTextPreviewLength ) ;
2019-10-08 14:21:05 +00:00
QAction * action = new QAction ( i18n ( " Search for '%1' in this document " , squeezedText ) , menu ) ;
2019-08-25 10:19:43 +00:00
action - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " document-preview " ) ) ) ;
2020-02-20 11:42:34 +00:00
connect ( action , & QAction : : triggered , this , [ this , searchText ] { Q_EMIT triggerSearch ( searchText ) ; } ) ;
2019-08-25 10:19:43 +00:00
menu - > addAction ( action ) ;
}
2020-09-11 21:19:36 +00:00
void PageView : : updateSmoothScrollAnimationSpeed ( )
{
2020-09-21 20:11:59 +00:00
// If it's turned off in Okular's own settings, don't bother to look at the
// global settings
if ( ! Okular : : Settings : : smoothScrolling ( ) ) {
d - > currentShortScrollDuration = 0 ;
d - > currentLongScrollDuration = 0 ;
return ;
}
// If we are using smooth scrolling, scale the speed of the animated
// transitions according to the global animation speed setting
2020-09-11 21:19:36 +00:00
KConfigGroup kdeglobalsConfig = KConfigGroup ( KSharedConfig : : openConfig ( ) , QStringLiteral ( " KDE " ) ) ;
const qreal globalAnimationScale = qMax ( 0.0 , kdeglobalsConfig . readEntry ( " AnimationDurationFactor " , 1.0 ) ) ;
d - > currentShortScrollDuration = d - > baseShortScrollDuration * globalAnimationScale ;
d - > currentLongScrollDuration = d - > baseLongScrollDuration * globalAnimationScale ;
}
2004-10-29 21:52:06 +00:00
// BEGIN private SLOTS
2004-09-30 18:04:09 +00:00
void PageView : : slotRelayoutPages ( )
2007-05-17 20:46:16 +00:00
// called by: notifySetup, viewportResizeEvent, slotViewMode, slotContinuousToggled, updateZoom
2004-09-27 21:36:25 +00:00
{
// set an empty container if we have no pages
2011-12-25 23:47:31 +00:00
const int pageCount = d - > items . count ( ) ;
2004-09-27 21:36:25 +00:00
if ( pageCount < 1 ) {
return ;
}
2006-10-07 14:40:32 +00:00
int viewportWidth = viewport ( ) - > width ( ) , viewportHeight = viewport ( ) - > height ( ) , fullWidth = 0 , fullHeight = 0 ;
2004-11-05 00:14:00 +00:00
2005-04-14 11:33:28 +00:00
// handle the 'center first page in row' stuff
2012-08-29 23:03:16 +00:00
const bool facing = Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : Facing & & pageCount > 1 ;
const bool facingCentered = Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : FacingFirstCentered | | ( Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : Facing & & pageCount = = 1 ) ;
2011-12-21 00:44:33 +00:00
const bool overrideCentering = facingCentered & & pageCount < 3 ;
const bool centerFirstPage = facingCentered & & ! overrideCentering ;
const bool facingPages = facing | | centerFirstPage ;
const bool centerLastPage = centerFirstPage & & pageCount % 2 = = 0 ;
2007-12-31 17:35:22 +00:00
const bool continuousView = Okular : : Settings : : viewContinuous ( ) ;
2011-12-25 23:47:31 +00:00
const int nCols = overrideCentering ? 1 : viewColumns ( ) ;
2015-03-16 23:20:11 +00:00
const bool singlePageViewMode = Okular : : Settings : : viewMode ( ) = = Okular : : Settings : : EnumViewMode : : Single ;
2015-05-21 23:47:16 +00:00
if ( d - > aFitWindowToPage )
d - > aFitWindowToPage - > setEnabled ( ! continuousView & & singlePageViewMode ) ;
2005-04-14 11:33:28 +00:00
2005-03-05 15:59:15 +00:00
// set all items geometry and resize contents. handle 'continuous' and 'single' modes separately
2007-12-31 17:35:22 +00:00
PageViewItem * currentItem = d - > items [ qMax ( 0 , ( int ) d - > document - > currentPage ( ) ) ] ;
2020-07-10 22:15:05 +00:00
2004-09-27 21:36:25 +00:00
// Here we find out column's width and row's height to compute a table
// so we can place widgets 'centered in virtual cells'.
2011-12-25 23:47:31 +00:00
const int nRows = ( int ) ceil ( ( float ) ( centerFirstPage ? ( pageCount + nCols - 1 ) : pageCount ) / ( float ) nCols ) ;
2020-07-10 22:15:05 +00:00
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
int * colWidth = new int [ nCols ] , * rowHeight = new int [ nRows ] , cIdx = 0 , rIdx = 0 ;
2004-09-27 21:36:25 +00:00
for ( int i = 0 ; i < nCols ; i + + )
colWidth [ i ] = viewportWidth / nCols ;
for ( int i = 0 ; i < nRows ; i + + )
rowHeight [ i ] = 0 ;
2005-04-14 11:33:28 +00:00
// handle the 'centering on first row' stuff
if ( centerFirstPage )
2007-12-31 17:35:22 +00:00
cIdx + = nCols - 1 ;
2020-07-10 22:15:05 +00:00
2004-09-27 21:36:25 +00:00
// 1) find the maximum columns width and rows height for a grid in
// which each page must well-fit inside a cell
2019-12-09 13:39:47 +00:00
for ( PageViewItem * item : qAsConst ( d - > items ) ) {
2004-10-30 20:54:48 +00:00
// update internal page size (leaving a little margin in case of Fit* modes)
2014-05-05 22:43:40 +00:00
updateItemSize ( item , colWidth [ cIdx ] - kcolWidthMargin , viewportHeight - krowHeightMargin ) ;
2004-09-27 21:36:25 +00:00
// find row's maximum height and column's max width
2014-05-05 22:43:40 +00:00
if ( item - > croppedWidth ( ) + kcolWidthMargin > colWidth [ cIdx ] )
colWidth [ cIdx ] = item - > croppedWidth ( ) + kcolWidthMargin ;
2004-09-27 21:36:25 +00:00
if ( item - > croppedHeight ( ) + krowHeightMargin > rowHeight [ rIdx ] )
2014-05-05 22:43:40 +00:00
rowHeight [ rIdx ] = item - > croppedHeight ( ) + krowHeightMargin ;
2005-04-14 11:33:28 +00:00
// handle the 'centering on first row' stuff
2004-10-30 20:54:48 +00:00
// update col/row indices
2004-09-27 21:36:25 +00:00
if ( + + cIdx = = nCols ) {
cIdx = 0 ;
rIdx + + ;
2004-09-26 23:39:39 +00:00
}
2020-07-10 22:15:05 +00:00
}
2004-09-27 21:36:25 +00:00
2007-12-31 17:35:22 +00:00
const int pageRowIdx = ( ( centerFirstPage ? nCols - 1 : 0 ) + currentItem - > pageNumber ( ) ) / nCols ;
2020-07-10 22:15:05 +00:00
2005-04-14 11:33:28 +00:00
// 2) compute full size
for ( int i = 0 ; i < nCols ; i + + )
fullWidth + = colWidth [ i ] ;
2007-12-31 17:35:22 +00:00
if ( continuousView ) {
for ( int i = 0 ; i < nRows ; i + + )
fullHeight + = rowHeight [ i ] ;
} else
fullHeight = rowHeight [ pageRowIdx ] ;
2020-07-10 22:15:05 +00:00
2005-04-14 11:33:28 +00:00
// 3) arrange widgets inside cells (and refine fullHeight if needed)
int insertX = 0 , insertY = fullHeight < viewportHeight ? ( viewportHeight - fullHeight ) / 2 : 0 ;
2007-12-31 17:35:22 +00:00
const int origInsertY = insertY ;
2004-10-30 20:54:48 +00:00
cIdx = 0 ;
rIdx = 0 ;
2007-12-31 17:35:22 +00:00
if ( centerFirstPage ) {
cIdx + = nCols - 1 ;
for ( int i = 0 ; i < cIdx ; + + i )
insertX + = colWidth [ i ] ;
}
2019-03-26 22:37:30 +00:00
for ( PageViewItem * item : qAsConst ( d - > items ) ) {
2004-10-30 20:54:48 +00:00
int cWidth = colWidth [ cIdx ] , rHeight = rowHeight [ rIdx ] ;
2007-12-31 17:35:22 +00:00
if ( continuousView | | rIdx = = pageRowIdx ) {
const bool reallyDoCenterFirst = item - > pageNumber ( ) = = 0 & & centerFirstPage ;
2011-12-21 00:44:33 +00:00
const bool reallyDoCenterLast = item - > pageNumber ( ) = = pageCount - 1 & & centerLastPage ;
2011-12-04 11:44:51 +00:00
int actualX = 0 ;
if ( reallyDoCenterFirst | | reallyDoCenterLast ) {
// page is centered across entire viewport
actualX = ( fullWidth - item - > croppedWidth ( ) ) / 2 ;
} else if ( facingPages ) {
2016-07-25 23:37:54 +00:00
if ( Okular : : Settings : : rtlReadingDirection ( ) ) {
// RTL reading mode
actualX = ( ( centerFirstPage & & item - > pageNumber ( ) % 2 = = 0 ) | | ( ! centerFirstPage & & item - > pageNumber ( ) % 2 = = 1 ) ) ? ( fullWidth / 2 ) - item - > croppedWidth ( ) - 1 : ( fullWidth / 2 ) + 1 ;
} else {
// page edges 'touch' the center of the viewport
actualX = ( ( centerFirstPage & & item - > pageNumber ( ) % 2 = = 1 ) | | ( ! centerFirstPage & & item - > pageNumber ( ) % 2 = = 0 ) ) ? ( fullWidth / 2 ) - item - > croppedWidth ( ) - 1 : ( fullWidth / 2 ) + 1 ;
2011-12-04 11:44:51 +00:00
}
} else {
// page is centered within its virtual column
2016-07-25 23:37:54 +00:00
// actualX = insertX + (cWidth - item->croppedWidth()) / 2;
if ( Okular : : Settings : : rtlReadingDirection ( ) ) {
actualX = fullWidth - insertX - cWidth + ( ( cWidth - item - > croppedWidth ( ) ) / 2 ) ;
} else {
actualX = insertX + ( cWidth - item - > croppedWidth ( ) ) / 2 ;
2011-12-04 11:44:51 +00:00
}
2004-09-27 21:36:25 +00:00
}
2008-05-19 00:37:14 +00:00
item - > moveTo ( actualX , ( continuousView ? insertY : origInsertY ) + ( rHeight - item - > croppedHeight ( ) ) / 2 ) ;
2007-12-31 17:35:22 +00:00
item - > setVisible ( true ) ;
2020-07-10 22:15:05 +00:00
} else {
2007-12-31 17:35:22 +00:00
item - > moveTo ( 0 , 0 ) ;
item - > setVisible ( false ) ;
2020-07-10 22:15:05 +00:00
}
2007-12-31 22:22:38 +00:00
item - > setFormWidgetsVisible ( d - > m_formsVisible ) ;
2004-09-27 21:36:25 +00:00
// advance col/row index
insertX + = cWidth ;
if ( + + cIdx = = nCols ) {
cIdx = 0 ;
2020-07-10 22:15:05 +00:00
rIdx + + ;
2004-09-27 21:36:25 +00:00
insertX = 0 ;
2005-04-14 11:33:28 +00:00
insertY + = rHeight ;
2020-07-10 22:15:05 +00:00
}
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# ifdef PAGEVIEW_DEBUG
2008-05-19 00:37:14 +00:00
kWarning ( ) < < " updating size for pageno " < < item - > pageNumber ( ) < < " cropped " < < item - > croppedGeometry ( ) < < " uncropped " < < item - > uncroppedGeometry ( ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# endif
2004-09-27 21:36:25 +00:00
}
delete [ ] colWidth ;
delete [ ] rowHeight ;
2004-09-30 18:16:12 +00:00
2004-11-05 00:14:00 +00:00
// 3) reset dirty state
d - > dirtyLayout = false ;
// 4) update scrollview's contents size and recenter view
2006-03-30 15:27:27 +00:00
bool wasUpdatesEnabled = viewport ( ) - > updatesEnabled ( ) ;
2009-06-29 20:55:50 +00:00
if ( fullWidth ! = contentAreaWidth ( ) | | fullHeight ! = contentAreaHeight ( ) ) {
2009-11-20 20:52:51 +00:00
const Okular : : DocumentViewport vp = d - > document - > viewport ( ) ;
2005-01-09 23:37:07 +00:00
// disable updates and resize the viewportContents
2005-01-10 13:43:44 +00:00
if ( wasUpdatesEnabled )
viewport ( ) - > setUpdatesEnabled ( false ) ;
2009-06-29 20:55:50 +00:00
resizeContentArea ( QSize ( fullWidth , fullHeight ) ) ;
2005-01-10 13:43:44 +00:00
// restore previous viewport if defined and updates enabled
if ( wasUpdatesEnabled ) {
if ( vp . pageNumber > = 0 ) {
2006-10-07 14:40:32 +00:00
int prevX = horizontalScrollBar ( ) - > value ( ) , prevY = verticalScrollBar ( ) - > value ( ) ;
Fix inconsistent viewport positioning in PageView
Summary:
This diff unifies the calculation of the viewport position from a given DocumentViewport. PageView::notifyViewportChanged and PageView::slotRelayoutPages used to handle it differntly, which resulted in viewport jumps for no reason.
It happened in various situations, e.g. when jumping to a page using the footer page navigation, or when reloading the document after presentation mode left, or when resizing the main window after presentation mode left.
The diff selects the notifyViewportChanged way (align viewport top border with page top margin) as golden behavior in case of rePos.enabled == false.
BUGS: 357958
CCBUG: 341939
CCBUG: 400890
341939 and 400890 are fixed partially. These two still suffer from a minor displacement that happens when finished signal arrives from pixmap generation thread.
Test Plan:
- When using the footer page navigation to jump to different pages, new page top is always algined with viewport top.
- After changing page with footer page navigation, press F5 to reload. Page top stays aligned with viewport top.
- When exiting presentation mode, and touching the file, page top stays aligned with viewport top.
- When exiting presentation mode, and changing main window size, page top stays aligned with viewport top.
Reviewers: #okular, sander
Reviewed By: sander
Subscribers: ngraham, sander, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16941
2018-11-22 17:50:14 +00:00
const QPoint centerPos = viewportToContentArea ( vp ) ;
center ( centerPos . x ( ) , centerPos . y ( ) ) ;
2005-06-13 10:37:41 +00:00
// center() usually moves the viewport, that requests pixmaps too.
// if that doesn't happen we have to request them by hand
2006-10-07 14:40:32 +00:00
if ( prevX = = horizontalScrollBar ( ) - > value ( ) & & prevY = = verticalScrollBar ( ) - > value ( ) )
2005-06-13 10:37:41 +00:00
slotRequestVisiblePixmaps ( ) ;
2005-01-10 13:43:44 +00:00
}
// or else go to center page
else
center ( fullWidth / 2 , 0 ) ;
viewport ( ) - > setUpdatesEnabled ( true ) ;
2004-11-05 00:14:00 +00:00
}
2004-09-26 23:39:39 +00:00
}
2004-09-27 21:36:25 +00:00
2005-01-10 13:43:44 +00:00
// 5) update the whole viewport if updated enabled
if ( wasUpdatesEnabled )
2009-06-29 20:55:50 +00:00
viewport ( ) - > update ( ) ;
2004-09-30 18:04:09 +00:00
}
2011-03-17 15:24:44 +00:00
void PageView : : delayedResizeEvent ( )
{
// If we already got here we don't need to execute the timer slot again
d - > delayResizeEventTimer - > stop ( ) ;
slotRelayoutPages ( ) ;
slotRequestVisiblePixmaps ( ) ;
}
2020-02-20 17:45:46 +00:00
static void slotRequestPreloadPixmap ( Okular : : DocumentObserver * observer , const PageViewItem * i , const QRect expandedViewportRect , QLinkedList < Okular : : PixmapRequest * > * requestedPixmaps )
2012-12-12 21:22:40 +00:00
{
Okular : : NormalizedRect preRenderRegion ;
2016-07-24 21:46:53 +00:00
const QRect intersectionRect = expandedViewportRect . intersected ( i - > croppedGeometry ( ) ) ;
2012-12-12 21:22:40 +00:00
if ( ! intersectionRect . isEmpty ( ) )
preRenderRegion = Okular : : NormalizedRect ( intersectionRect . translated ( - i - > uncroppedGeometry ( ) . topLeft ( ) ) , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) ) ;
// request the pixmap if not already present
2013-02-24 21:58:53 +00:00
if ( ! i - > page ( ) - > hasPixmap ( observer , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) , preRenderRegion ) & & i - > uncroppedWidth ( ) > 0 ) {
Okular : : PixmapRequest : : PixmapRequestFeatures requestFeatures = Okular : : PixmapRequest : : Preload ;
requestFeatures | = Okular : : PixmapRequest : : Asynchronous ;
2014-02-19 22:40:43 +00:00
const bool pageHasTilesManager = i - > page ( ) - > hasTilesManager ( observer ) ;
2012-12-12 21:22:40 +00:00
if ( pageHasTilesManager & & ! preRenderRegion . isNull ( ) ) {
2013-02-24 21:58:53 +00:00
Okular : : PixmapRequest * p = new Okular : : PixmapRequest ( observer , i - > pageNumber ( ) , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) , PAGEVIEW_PRELOAD_PRIO , requestFeatures ) ;
2012-12-12 21:22:40 +00:00
requestedPixmaps - > push_back ( p ) ;
2020-07-10 22:15:05 +00:00
2012-12-12 21:22:40 +00:00
p - > setNormalizedRect ( preRenderRegion ) ;
p - > setTile ( true ) ;
} else if ( ! pageHasTilesManager ) {
2013-02-24 21:58:53 +00:00
Okular : : PixmapRequest * p = new Okular : : PixmapRequest ( observer , i - > pageNumber ( ) , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) , PAGEVIEW_PRELOAD_PRIO , requestFeatures ) ;
2012-12-12 21:22:40 +00:00
requestedPixmaps - > push_back ( p ) ;
p - > setNormalizedRect ( preRenderRegion ) ;
}
}
}
2008-04-16 11:04:59 +00:00
void PageView : : slotRequestVisiblePixmaps ( int newValue )
2004-09-30 18:16:12 +00:00
{
2005-01-21 20:05:36 +00:00
// if requests are blocked (because raised by an unwanted event), exit
2020-08-16 14:21:35 +00:00
if ( d - > blockPixmapsRequest )
2005-01-21 20:05:36 +00:00
return ;
2011-12-13 18:52:33 +00:00
// precalc view limits for intersecting with page coords inside the loop
2011-12-13 18:52:19 +00:00
const bool isEvent = newValue ! = - 1 & & ! d - > blockViewport ;
const QRect viewportRect ( horizontalScrollBar ( ) - > value ( ) , verticalScrollBar ( ) - > value ( ) , viewport ( ) - > width ( ) , viewport ( ) - > height ( ) ) ;
2011-12-13 18:50:46 +00:00
const QRect viewportRectAtZeroZero ( 0 , 0 , viewport ( ) - > width ( ) , viewport ( ) - > height ( ) ) ;
2004-09-30 18:16:12 +00:00
2005-01-09 23:37:07 +00:00
// some variables used to determine the viewport
2005-01-28 17:21:28 +00:00
int nearPageNumber = - 1 ;
2011-12-13 18:52:19 +00:00
const double viewportCenterX = ( viewportRect . left ( ) + viewportRect . right ( ) ) / 2.0 ;
const double viewportCenterY = ( viewportRect . top ( ) + viewportRect . bottom ( ) ) / 2.0 ;
double focusedX = 0.5 , focusedY = 0.0 , minDistance = - 1.0 ;
2012-11-12 02:09:12 +00:00
// Margin (in pixels) around the viewport to preload
const int pixelsToExpand = 512 ;
2005-01-09 23:37:07 +00:00
// iterate over all items
2004-12-21 12:38:52 +00:00
d - > visibleItems . clear ( ) ;
2006-09-21 08:45:36 +00:00
QLinkedList < Okular : : PixmapRequest * > requestedPixmaps ;
QVector < Okular : : VisiblePageRect * > visibleRects ;
2019-03-26 22:37:30 +00:00
for ( PageViewItem * i : qAsConst ( d - > items ) ) {
2019-12-09 13:39:47 +00:00
const QSet < FormWidgetIface * > formWidgetsList = i - > formWidgets ( ) ;
for ( FormWidgetIface * fwi : formWidgetsList ) {
2009-06-29 20:55:50 +00:00
Okular : : NormalizedRect r = fwi - > rect ( ) ;
fwi - > moveTo ( qRound ( i - > uncroppedGeometry ( ) . left ( ) + i - > uncroppedWidth ( ) * r . left ) + 1 - viewportRect . left ( ) , qRound ( i - > uncroppedGeometry ( ) . top ( ) + i - > uncroppedHeight ( ) * r . top ) + 1 - viewportRect . top ( ) ) ;
}
2019-12-09 13:39:47 +00:00
const QHash < Okular : : Movie * , VideoWidget * > videoWidgets = i - > videoWidgets ( ) ;
for ( VideoWidget * vw : videoWidgets ) {
2009-06-29 20:55:50 +00:00
const Okular : : NormalizedRect r = vw - > normGeometry ( ) ;
vw - > move ( qRound ( i - > uncroppedGeometry ( ) . left ( ) + i - > uncroppedWidth ( ) * r . left ) + 1 - viewportRect . left ( ) , qRound ( i - > uncroppedGeometry ( ) . top ( ) + i - > uncroppedHeight ( ) * r . top ) + 1 - viewportRect . top ( ) ) ;
2013-04-05 22:22:48 +00:00
2016-07-24 21:46:53 +00:00
if ( vw - > isPlaying ( ) & & viewportRectAtZeroZero . intersected ( vw - > geometry ( ) ) . isEmpty ( ) ) {
2011-12-13 18:50:46 +00:00
vw - > stop ( ) ;
2012-06-29 09:16:28 +00:00
vw - > pageLeft ( ) ;
2011-12-13 18:50:46 +00:00
}
2009-06-29 20:55:50 +00:00
}
2007-12-31 17:35:22 +00:00
if ( ! i - > isVisible ( ) )
continue ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# ifdef PAGEVIEW_DEBUG
2007-07-31 10:19:48 +00:00
kWarning ( ) < < " checking page " < < i - > pageNumber ( ) ;
2008-05-19 00:37:14 +00:00
kWarning ( ) . nospace ( ) < < " viewportRect is " < < viewportRect < < " , page item is " < < i - > croppedGeometry ( ) < < " intersect : " < < viewportRect . intersects ( i - > croppedGeometry ( ) ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# endif
2005-01-09 23:37:07 +00:00
// if the item doesn't intersect the viewport, skip it
2016-07-24 21:46:53 +00:00
QRect intersectionRect = viewportRect . intersected ( i - > croppedGeometry ( ) ) ;
2006-06-23 21:11:52 +00:00
if ( intersectionRect . isEmpty ( ) ) {
2004-12-22 18:21:36 +00:00
continue ;
2012-08-20 01:43:59 +00:00
}
2004-12-22 18:21:36 +00:00
2005-01-09 23:37:07 +00:00
// add the item to the 'visible list'
2004-12-22 18:21:36 +00:00
d - > visibleItems . push_back ( i ) ;
2008-05-19 00:37:14 +00:00
Okular : : VisiblePageRect * vItem = new Okular : : VisiblePageRect ( i - > pageNumber ( ) , Okular : : NormalizedRect ( intersectionRect . translated ( - i - > uncroppedGeometry ( ) . topLeft ( ) ) , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) ) ) ;
2006-06-23 21:11:52 +00:00
visibleRects . push_back ( vItem ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# ifdef PAGEVIEW_DEBUG
2013-10-01 14:34:09 +00:00
kWarning ( ) < < " checking for pixmap for page " < < i - > pageNumber ( ) < < " = " < < i - > page ( ) - > hasPixmap ( this , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) ) ;
2007-07-31 10:19:48 +00:00
kWarning ( ) < < " checking for text for page " < < i - > pageNumber ( ) < < " = " < < i - > page ( ) - > hasTextPage ( ) ;
2006-11-24 21:44:25 +00:00
# endif
2012-08-10 19:00:50 +00:00
2012-08-24 16:23:37 +00:00
Okular : : NormalizedRect expandedVisibleRect = vItem - > rect ;
2014-02-19 22:40:43 +00:00
if ( i - > page ( ) - > hasTilesManager ( this ) & & Okular : : Settings : : memoryLevel ( ) ! = Okular : : Settings : : EnumMemoryLevel : : Low ) {
2012-08-20 03:40:47 +00:00
double rectMargin = pixelsToExpand / ( double ) i - > uncroppedHeight ( ) ;
expandedVisibleRect . left = qMax ( 0.0 , vItem - > rect . left - rectMargin ) ;
expandedVisibleRect . top = qMax ( 0.0 , vItem - > rect . top - rectMargin ) ;
expandedVisibleRect . right = qMin ( 1.0 , vItem - > rect . right + rectMargin ) ;
expandedVisibleRect . bottom = qMin ( 1.0 , vItem - > rect . bottom + rectMargin ) ;
2012-08-10 19:00:50 +00:00
}
2005-01-09 23:37:07 +00:00
// if the item has not the right pixmap, add a request for it
2013-02-24 21:58:53 +00:00
if ( ! i - > page ( ) - > hasPixmap ( this , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) , expandedVisibleRect ) ) {
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# ifdef PAGEVIEW_DEBUG
2007-07-31 10:19:48 +00:00
kWarning ( ) < < " rerequesting visible pixmaps for page " < < i - > pageNumber ( ) < < " ! " ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
# endif
2013-02-24 21:58:53 +00:00
Okular : : PixmapRequest * p = new Okular : : PixmapRequest ( this , i - > pageNumber ( ) , i - > uncroppedWidth ( ) , i - > uncroppedHeight ( ) , PAGEVIEW_PRIO , Okular : : PixmapRequest : : Asynchronous ) ;
2012-07-19 03:30:03 +00:00
requestedPixmaps . push_back ( p ) ;
2020-07-10 22:15:05 +00:00
2014-02-19 22:40:43 +00:00
if ( i - > page ( ) - > hasTilesManager ( this ) ) {
2012-11-12 14:55:13 +00:00
p - > setNormalizedRect ( expandedVisibleRect ) ;
2012-08-24 16:32:39 +00:00
p - > setTile ( true ) ;
2012-11-12 02:09:12 +00:00
} else
p - > setNormalizedRect ( vItem - > rect ) ;
2005-01-18 16:43:36 +00:00
}
2005-01-09 23:37:07 +00:00
// look for the item closest to viewport center and the relative
// position between the item and the viewport center
if ( isEvent ) {
2008-05-19 00:37:14 +00:00
const QRect & geometry = i - > croppedGeometry ( ) ;
2005-04-14 11:33:28 +00:00
// compute distance between item center and viewport center (slightly moved left)
2019-12-23 13:57:50 +00:00
const double distance = hypot ( ( geometry . left ( ) + geometry . right ( ) ) / 2.0 - ( viewportCenterX - 4 ) , ( geometry . top ( ) + geometry . bottom ( ) ) / 2.0 - viewportCenterY ) ;
2005-01-09 23:37:07 +00:00
if ( distance > = minDistance & & nearPageNumber ! = - 1 )
continue ;
nearPageNumber = i - > pageNumber ( ) ;
minDistance = distance ;
if ( geometry . height ( ) > 0 & & geometry . width ( ) > 0 ) {
2005-01-28 17:21:28 +00:00
focusedX = ( viewportCenterX - ( double ) geometry . left ( ) ) / ( double ) geometry . width ( ) ;
focusedY = ( viewportCenterY - ( double ) geometry . top ( ) ) / ( double ) geometry . height ( ) ;
2005-01-09 23:37:07 +00:00
}
}
2004-12-21 12:38:52 +00:00
}
2005-01-20 17:33:05 +00:00
// if preloading is enabled, add the pages before and after in preloading
2012-10-15 22:27:42 +00:00
if ( ! d - > visibleItems . isEmpty ( ) & & Okular : : SettingsCore : : memoryLevel ( ) ! = Okular : : SettingsCore : : EnumMemoryLevel : : Low ) {
2007-01-04 21:47:54 +00:00
// as the requests are done in the order as they appear in the list,
// request first the next page and then the previous
2009-10-23 18:04:03 +00:00
int pagesToPreload = viewColumns ( ) ;
2012-03-08 23:12:20 +00:00
// if the greedy option is set, preload all pages
2012-10-15 22:27:42 +00:00
if ( Okular : : SettingsCore : : memoryLevel ( ) = = Okular : : SettingsCore : : EnumMemoryLevel : : Greedy )
2012-03-08 23:12:20 +00:00
pagesToPreload = d - > items . count ( ) ;
2012-12-12 21:16:28 +00:00
const QRect expandedViewportRect = viewportRect . adjusted ( 0 , - pixelsToExpand , 0 , pixelsToExpand ) ;
2012-08-20 03:40:47 +00:00
2009-10-23 18:04:03 +00:00
for ( int j = 1 ; j < = pagesToPreload ; j + + ) {
// add the page after the 'visible series' in preload
2012-12-12 21:16:28 +00:00
const int tailRequest = d - > visibleItems . last ( ) - > pageNumber ( ) + j ;
2009-10-23 18:04:03 +00:00
if ( tailRequest < ( int ) d - > items . count ( ) ) {
2013-02-24 21:58:53 +00:00
slotRequestPreloadPixmap ( this , d - > items [ tailRequest ] , expandedViewportRect , & requestedPixmaps ) ;
2009-10-23 18:04:03 +00:00
}
2005-01-20 17:33:05 +00:00
2009-10-23 18:04:03 +00:00
// add the page before the 'visible series' in preload
2012-12-12 21:16:28 +00:00
const int headRequest = d - > visibleItems . first ( ) - > pageNumber ( ) - j ;
2009-10-23 18:04:03 +00:00
if ( headRequest > = 0 ) {
2013-02-24 21:58:53 +00:00
slotRequestPreloadPixmap ( this , d - > items [ headRequest ] , expandedViewportRect , & requestedPixmaps ) ;
2009-10-23 18:04:03 +00:00
}
2012-07-02 06:28:23 +00:00
// stop if we've already reached both ends of the document
if ( headRequest < 0 & & tailRequest > = ( int ) d - > items . count ( ) )
break ;
2005-01-18 16:43:36 +00:00
}
}
2005-01-09 23:37:07 +00:00
2005-01-20 17:33:05 +00:00
// send requests to the document
if ( ! requestedPixmaps . isEmpty ( ) ) {
d - > document - > requestPixmaps ( requestedPixmaps ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
}
2005-01-28 17:21:28 +00:00
// if this functions was invoked by viewport events, send update to document
2005-01-09 23:37:07 +00:00
if ( isEvent & & nearPageNumber ! = - 1 ) {
// determine the document viewport
2006-09-21 08:45:36 +00:00
Okular : : DocumentViewport newViewport ( nearPageNumber ) ;
2005-06-13 11:53:47 +00:00
newViewport . rePos . enabled = true ;
newViewport . rePos . normalizedX = focusedX ;
newViewport . rePos . normalizedY = focusedY ;
2005-01-09 23:37:07 +00:00
// set the viewport to other observers
2020-08-16 14:21:35 +00:00
// do not update history if the viewport is autoscrolling
2020-10-18 21:24:02 +00:00
d - > document - > setViewportWithHistory ( newViewport , this , false , d - > scroller - > state ( ) ! = QScroller : : Scrolling ) ;
2005-01-09 23:37:07 +00:00
}
2013-02-24 21:58:53 +00:00
d - > document - > setVisiblePageRects ( visibleRects , this ) ;
2004-09-30 18:16:12 +00:00
}
2004-10-06 00:05:49 +00:00
2016-10-01 10:52:30 +00:00
void PageView : : slotAutoScroll ( )
2004-10-06 00:05:49 +00:00
{
// the first time create the timer
2005-02-01 18:24:16 +00:00
if ( ! d - > autoScrollTimer ) {
d - > autoScrollTimer = new QTimer ( this ) ;
2006-05-28 21:52:36 +00:00
d - > autoScrollTimer - > setSingleShot ( true ) ;
2016-10-01 10:52:30 +00:00
connect ( d - > autoScrollTimer , & QTimer : : timeout , this , & PageView : : slotAutoScroll ) ;
2004-10-06 00:05:49 +00:00
}
// if scrollIncrement is zero, stop the timer
if ( ! d - > scrollIncrement ) {
2005-02-01 18:24:16 +00:00
d - > autoScrollTimer - > stop ( ) ;
2004-10-06 00:05:49 +00:00
return ;
}
// compute delay between timer ticks and scroll amount per tick
int index = abs ( d - > scrollIncrement ) - 1 ; // 0..9
const int scrollDelay [ 10 ] = { 200 , 100 , 50 , 30 , 20 , 30 , 25 , 20 , 30 , 20 } ;
const int scrollOffset [ 10 ] = { 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 4 , 4 } ;
2006-05-28 21:52:36 +00:00
d - > autoScrollTimer - > start ( scrollDelay [ index ] ) ;
2006-10-07 14:40:32 +00:00
int delta = d - > scrollIncrement > 0 ? scrollOffset [ index ] : - scrollOffset [ index ] ;
2019-11-15 16:08:25 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( 0 , delta ) , scrollDelay [ index ] ) ;
2004-10-06 00:05:49 +00:00
}
2004-09-30 18:16:12 +00:00
2006-11-22 21:32:21 +00:00
void PageView : : slotDragScroll ( )
{
2012-09-03 00:55:16 +00:00
scrollTo ( horizontalScrollBar ( ) - > value ( ) + d - > dragScrollVector . x ( ) , verticalScrollBar ( ) - > value ( ) + d - > dragScrollVector . y ( ) ) ;
2009-06-29 20:55:50 +00:00
QPoint p = contentAreaPosition ( ) + viewport ( ) - > mapFromGlobal ( QCursor : : pos ( ) ) ;
2012-09-28 15:57:03 +00:00
updateSelection ( p ) ;
2006-11-22 21:32:21 +00:00
}
2006-09-20 13:58:28 +00:00
void PageView : : slotShowWelcome ( )
{
// show initial welcome text
2010-08-21 15:46:47 +00:00
d - > messageWindow - > display ( i18n ( " Welcome " ) , QString ( ) , PageViewMessage : : Info , 2000 ) ;
2006-09-20 13:58:28 +00:00
}
2010-03-25 20:59:16 +00:00
void PageView : : slotShowSizeAllCursor ( )
{
setCursor ( Qt : : SizeAllCursor ) ;
}
2010-09-11 13:34:22 +00:00
void PageView : : slotHandleWebShortcutAction ( )
{
2016-07-24 20:12:26 +00:00
QAction * action = qobject_cast < QAction * > ( sender ( ) ) ;
2010-09-11 13:34:22 +00:00
2016-07-24 20:12:26 +00:00
if ( action ) {
2010-09-11 13:34:22 +00:00
KUriFilterData filterData ( action - > data ( ) . toString ( ) ) ;
2016-07-24 20:12:26 +00:00
if ( KUriFilter : : self ( ) - > filterSearchUri ( filterData , KUriFilter : : WebShortcutFilter ) ) {
2016-07-24 20:31:34 +00:00
QDesktopServices : : openUrl ( filterData . uri ( ) ) ;
2010-09-11 13:34:22 +00:00
}
}
}
void PageView : : slotConfigureWebShortcuts ( )
{
2017-01-11 16:05:55 +00:00
KToolInvocation : : kdeinitExec ( QStringLiteral ( " kcmshell5 " ) , QStringList ( ) < < QStringLiteral ( " webshortcuts " ) ) ;
2010-09-11 13:34:22 +00:00
}
2004-10-29 21:52:06 +00:00
void PageView : : slotZoom ( )
2004-09-30 18:04:09 +00:00
{
2011-10-23 09:17:04 +00:00
if ( ! d - > aZoom - > selectableActionGroup ( ) - > isEnabled ( ) )
return ;
2004-12-13 18:21:37 +00:00
setFocus ( ) ;
2004-10-29 21:52:06 +00:00
updateZoom ( ZoomFixed ) ;
}
2004-10-20 16:41:13 +00:00
2004-10-29 21:52:06 +00:00
void PageView : : slotZoomIn ( )
{
updateZoom ( ZoomIn ) ;
}
2004-09-30 18:04:09 +00:00
2004-10-29 21:52:06 +00:00
void PageView : : slotZoomOut ( )
{
updateZoom ( ZoomOut ) ;
}
2004-09-30 18:04:09 +00:00
Create new "Zoom to 100%" action
Summary:
This patch implements a "Zoom to 100%" action and sticks it in the {nav View} menu. Since it's a `KStandardAction` with a `KStandardShortcut`, we automatically get the correct icon and keyboard shortcut, but we do override the name to be "Zoom to 100%" since that's clearer for Okular's use case.
FEATURE: 400048
FIXED-IN: 18.12.0
Test Plan:
- Action works to zoom the document to 100% scale when invoked
- Action is disabled when document is opened at 100% scale or is manually zoomed to 100% scale after being opened
- All other zoom modes and action still work
{F6341045}
Reviewers: #okular, #vdg, abetts
Reviewed By: #vdg, abetts
Subscribers: davidhurka, sander, tobiasdeiminger, veqz, abetts, aacid, okular-devel
Tags: #okular
Differential Revision: https://phabricator.kde.org/D16345
2018-10-21 03:54:49 +00:00
void PageView : : slotZoomActual ( )
{
updateZoom ( ZoomActual ) ;
}
2004-10-29 21:52:06 +00:00
void PageView : : slotFitToWidthToggled ( bool on )
{
if ( on )
updateZoom ( ZoomFitWidth ) ;
2004-09-30 18:04:09 +00:00
}
2004-10-29 21:52:06 +00:00
void PageView : : slotFitToPageToggled ( bool on )
2004-09-30 18:04:09 +00:00
{
2004-10-29 21:52:06 +00:00
if ( on )
updateZoom ( ZoomFitPage ) ;
}
2004-09-30 18:04:09 +00:00
2013-08-18 15:19:20 +00:00
void PageView : : slotAutoFitToggled ( bool on )
{
if ( on )
updateZoom ( ZoomFitAuto ) ;
}
2008-10-12 16:36:14 +00:00
void PageView : : slotViewMode ( QAction * action )
2004-10-29 21:52:06 +00:00
{
2008-10-12 16:36:14 +00:00
const int nr = action - > data ( ) . toInt ( ) ;
2007-05-17 20:46:16 +00:00
if ( ( int ) Okular : : Settings : : viewMode ( ) ! = nr ) {
Okular : : Settings : : setViewMode ( nr ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2004-10-29 21:52:06 +00:00
if ( d - > document - > pages ( ) > 0 )
slotRelayoutPages ( ) ;
2004-09-30 18:04:09 +00:00
}
2004-09-26 23:39:39 +00:00
}
2005-03-05 15:59:15 +00:00
void PageView : : slotContinuousToggled ( bool on )
2004-09-28 13:53:47 +00:00
{
2006-09-21 08:45:36 +00:00
if ( Okular : : Settings : : viewContinuous ( ) ! = on ) {
Okular : : Settings : : setViewContinuous ( on ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2004-10-29 21:52:06 +00:00
if ( d - > document - > pages ( ) > 0 )
slotRelayoutPages ( ) ;
2004-09-28 13:53:47 +00:00
}
}
2020-07-14 10:03:47 +00:00
void PageView : : slotReadingDirectionToggled ( bool leftToRight )
{
Okular : : Settings : : setRtlReadingDirection ( leftToRight ) ;
Okular : : Settings : : self ( ) - > save ( ) ;
}
void PageView : : slotUpdateReadingDirectionAction ( )
{
d - > aReadingDirection - > setChecked ( Okular : : Settings : : rtlReadingDirection ( ) ) ;
}
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
void PageView : : slotMouseNormalToggled ( bool checked )
2004-09-26 23:39:39 +00:00
{
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
if ( checked ) {
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : Browse ;
Okular : : Settings : : setMouseMode ( d - > mouseMode ) ;
// hide the messageWindow
d - > messageWindow - > hide ( ) ;
// force an update of the cursor
updateCursor ( ) ;
Okular : : Settings : : self ( ) - > save ( ) ;
} else {
d - > annotator - > detachAnnotation ( ) ;
}
2004-11-03 17:35:48 +00:00
}
void PageView : : slotSetMouseZoom ( )
{
2014-12-10 14:33:27 +00:00
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : Zoom ;
Okular : : Settings : : setMouseMode ( d - > mouseMode ) ;
2005-02-12 17:42:54 +00:00
// change the text in messageWindow (and show it if hidden)
2010-08-21 15:46:47 +00:00
d - > messageWindow - > display ( i18n ( " Select zooming area. Right-click to zoom out. " ) , QString ( ) , PageViewMessage : : Info , - 1 ) ;
2007-09-14 16:02:02 +00:00
// force an update of the cursor
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2004-09-26 23:39:39 +00:00
}
2014-02-24 22:42:10 +00:00
void PageView : : slotSetMouseMagnifier ( )
{
2014-12-10 14:33:27 +00:00
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : Magnifier ;
Okular : : Settings : : setMouseMode ( d - > mouseMode ) ;
2014-02-24 22:42:10 +00:00
d - > messageWindow - > display ( i18n ( " Click to see the magnified view. " ) , QString ( ) ) ;
// force an update of the cursor
updateCursor ( ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2014-02-24 22:42:10 +00:00
}
2004-11-16 17:36:02 +00:00
void PageView : : slotSetMouseSelect ( )
2004-09-26 23:39:39 +00:00
{
2014-12-10 14:33:27 +00:00
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : RectSelect ;
Okular : : Settings : : setMouseMode ( d - > mouseMode ) ;
2005-02-12 17:42:54 +00:00
// change the text in messageWindow (and show it if hidden)
2010-08-21 15:46:47 +00:00
d - > messageWindow - > display ( i18n ( " Draw a rectangle around the text/graphics to copy. " ) , QString ( ) , PageViewMessage : : Info , - 1 ) ;
2007-09-14 16:02:02 +00:00
// force an update of the cursor
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2005-02-18 18:24:45 +00:00
}
2006-09-26 22:22:01 +00:00
void PageView : : slotSetMouseTextSelect ( )
{
2014-12-10 14:33:27 +00:00
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : TextSelect ;
Okular : : Settings : : setMouseMode ( d - > mouseMode ) ;
2006-09-26 22:22:01 +00:00
// change the text in messageWindow (and show it if hidden)
2010-08-21 15:46:47 +00:00
d - > messageWindow - > display ( i18n ( " Select text " ) , QString ( ) , PageViewMessage : : Info , - 1 ) ;
2007-09-14 16:02:02 +00:00
// force an update of the cursor
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2006-09-26 22:22:01 +00:00
}
2011-10-12 13:50:56 +00:00
void PageView : : slotSetMouseTableSelect ( )
{
2014-12-10 14:33:27 +00:00
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : TableSelect ;
Okular : : Settings : : setMouseMode ( d - > mouseMode ) ;
2011-10-12 13:50:56 +00:00
// change the text in messageWindow (and show it if hidden)
d - > messageWindow - > display ( i18n ( " Draw a rectangle around the table, then click near edges to divide up; press Esc to clear. " ) , QString ( ) , PageViewMessage : : Info , - 1 ) ;
// force an update of the cursor
2013-06-23 18:42:19 +00:00
updateCursor ( ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2011-10-12 13:50:56 +00:00
}
2012-09-05 20:12:11 +00:00
void PageView : : slotAutoScrollUp ( )
2004-09-26 23:39:39 +00:00
{
2004-10-29 21:52:06 +00:00
if ( d - > scrollIncrement < - 9 )
return ;
d - > scrollIncrement - - ;
2016-10-01 10:52:30 +00:00
slotAutoScroll ( ) ;
2004-10-30 20:54:48 +00:00
setFocus ( ) ;
2004-10-29 21:52:06 +00:00
}
2012-09-05 20:12:11 +00:00
void PageView : : slotAutoScrollDown ( )
2004-10-29 21:52:06 +00:00
{
if ( d - > scrollIncrement > 9 )
return ;
d - > scrollIncrement + + ;
2016-10-01 10:52:30 +00:00
slotAutoScroll ( ) ;
2004-10-30 20:54:48 +00:00
setFocus ( ) ;
2004-09-26 23:39:39 +00:00
}
2007-01-19 21:43:53 +00:00
2019-11-15 16:08:25 +00:00
void PageView : : slotScrollUp ( int nSteps )
2012-09-05 20:12:11 +00:00
{
// if in single page mode and at the top of the screen, go to \ page
if ( Okular : : Settings : : viewContinuous ( ) | | verticalScrollBar ( ) - > value ( ) > verticalScrollBar ( ) - > minimum ( ) ) {
2019-11-15 16:08:25 +00:00
if ( nSteps ) {
2020-09-11 21:19:36 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( 0 , - 100 * nSteps ) , d - > currentShortScrollDuration ) ;
2019-11-15 16:08:25 +00:00
} else {
if ( d - > scroller - > finalPosition ( ) . y ( ) > verticalScrollBar ( ) - > minimum ( ) )
2020-09-29 15:36:56 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( 0 , - ( 1 - Okular : : Settings : : scrollOverlap ( ) / 100.0 ) * verticalScrollBar ( ) - > rect ( ) . height ( ) ) , d - > currentLongScrollDuration ) ;
2019-11-15 16:08:25 +00:00
}
2012-09-05 20:12:11 +00:00
} else if ( d - > document - > currentPage ( ) > 0 ) {
// more optimized than document->setPrevPage and then move view to bottom
Okular : : DocumentViewport newViewport = d - > document - > viewport ( ) ;
newViewport . pageNumber - = viewColumns ( ) ;
if ( newViewport . pageNumber < 0 )
newViewport . pageNumber = 0 ;
newViewport . rePos . enabled = true ;
newViewport . rePos . normalizedY = 1.0 ;
d - > document - > setViewport ( newViewport ) ;
}
}
2019-11-15 16:08:25 +00:00
void PageView : : slotScrollDown ( int nSteps )
2012-09-05 20:12:11 +00:00
{
// if in single page mode and at the bottom of the screen, go to next page
if ( Okular : : Settings : : viewContinuous ( ) | | verticalScrollBar ( ) - > value ( ) < verticalScrollBar ( ) - > maximum ( ) ) {
2019-11-15 16:08:25 +00:00
if ( nSteps ) {
2020-09-11 21:19:36 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( 0 , 100 * nSteps ) , d - > currentShortScrollDuration ) ;
2019-11-15 16:08:25 +00:00
} else {
if ( d - > scroller - > finalPosition ( ) . y ( ) < verticalScrollBar ( ) - > maximum ( ) )
2020-09-29 15:36:56 +00:00
d - > scroller - > scrollTo ( d - > scroller - > finalPosition ( ) + QPoint ( 0 , ( 1 - Okular : : Settings : : scrollOverlap ( ) / 100.0 ) * verticalScrollBar ( ) - > rect ( ) . height ( ) ) , d - > currentLongScrollDuration ) ;
2019-11-15 16:08:25 +00:00
}
2012-09-05 20:12:11 +00:00
} else if ( ( int ) d - > document - > currentPage ( ) < d - > items . count ( ) - 1 ) {
// more optimized than document->setNextPage and then move view to top
Okular : : DocumentViewport newViewport = d - > document - > viewport ( ) ;
newViewport . pageNumber + = viewColumns ( ) ;
if ( newViewport . pageNumber > = ( int ) d - > items . count ( ) )
newViewport . pageNumber = d - > items . count ( ) - 1 ;
newViewport . rePos . enabled = true ;
newViewport . rePos . normalizedY = 0.0 ;
d - > document - > setViewport ( newViewport ) ;
}
}
2007-01-19 21:43:53 +00:00
void PageView : : slotRotateClockwise ( )
{
int id = ( ( int ) d - > document - > rotation ( ) + 1 ) % 4 ;
2007-05-01 23:09:45 +00:00
d - > document - > setRotation ( id ) ;
2007-01-19 21:43:53 +00:00
}
void PageView : : slotRotateCounterClockwise ( )
{
int id = ( ( int ) d - > document - > rotation ( ) + 3 ) % 4 ;
2007-05-01 23:09:45 +00:00
d - > document - > setRotation ( id ) ;
2007-01-19 21:43:53 +00:00
}
void PageView : : slotRotateOriginal ( )
{
2007-05-01 23:09:45 +00:00
d - > document - > setRotation ( 0 ) ;
2007-01-19 21:43:53 +00:00
}
2007-02-25 00:07:59 +00:00
2015-08-27 20:09:02 +00:00
// Enforce mutual-exclusion between trim modes
// Each mode is uniquely identified by a single value
// From Okular::Settings::EnumTrimMode
void PageView : : updateTrimMode ( int except_id )
{
const QList < QAction * > trimModeActions = d - > aTrimMode - > menu ( ) - > actions ( ) ;
2019-12-09 13:39:47 +00:00
for ( QAction * trimModeAction : trimModeActions ) {
2015-08-27 20:09:02 +00:00
if ( trimModeAction - > data ( ) . toInt ( ) ! = except_id )
trimModeAction - > setChecked ( false ) ;
}
}
2017-09-21 20:16:31 +00:00
bool PageView : : mouseReleaseOverLink ( const Okular : : ObjectRect * rect ) const
{
if ( rect ) {
// handle click over a link
const Okular : : Action * action = static_cast < const Okular : : Action * > ( rect - > object ( ) ) ;
d - > document - > processAction ( action ) ;
return true ;
}
return false ;
}
2008-05-27 14:00:59 +00:00
void PageView : : slotTrimMarginsToggled ( bool on )
2008-05-19 00:37:14 +00:00
{
2015-08-27 20:09:02 +00:00
if ( on ) { // Turn off any other Trim modes
updateTrimMode ( d - > aTrimMargins - > data ( ) . toInt ( ) ) ;
}
2008-05-27 14:00:59 +00:00
if ( Okular : : Settings : : trimMargins ( ) ! = on ) {
Okular : : Settings : : setTrimMargins ( on ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2008-05-19 00:37:14 +00:00
if ( d - > document - > pages ( ) > 0 ) {
slotRelayoutPages ( ) ;
slotRequestVisiblePixmaps ( ) ; // TODO: slotRelayoutPages() may have done this already!
}
}
}
2015-08-27 20:09:02 +00:00
void PageView : : slotTrimToSelectionToggled ( bool on )
{
if ( on ) { // Turn off any other Trim modes
updateTrimMode ( d - > aTrimToSelection - > data ( ) . toInt ( ) ) ;
d - > mouseMode = Okular : : Settings : : EnumMouseMode : : TrimSelect ;
// change the text in messageWindow (and show it if hidden)
d - > messageWindow - > display ( i18n ( " Draw a rectangle around the page area you wish to keep visible " ) , QString ( ) , PageViewMessage : : Info , - 1 ) ;
// force an update of the cursor
updateCursor ( ) ;
} else {
// toggled off while making selection
if ( Okular : : Settings : : EnumMouseMode : : TrimSelect = = d - > mouseMode ) {
// clear widget selection and invalidate rect
selectionClear ( ) ;
// When Trim selection bbox interaction is over, we should switch to another mousemode.
if ( d - > aPrevAction ) {
d - > aPrevAction - > trigger ( ) ;
2017-09-05 21:27:18 +00:00
d - > aPrevAction = nullptr ;
2015-08-27 20:09:02 +00:00
} else {
d - > aMouseNormal - > trigger ( ) ;
}
}
d - > trimBoundingBox = Okular : : NormalizedRect ( ) ; // invalidate box
2008-05-19 00:37:14 +00:00
if ( d - > document - > pages ( ) > 0 ) {
slotRelayoutPages ( ) ;
slotRequestVisiblePixmaps ( ) ; // TODO: slotRelayoutPages() may have done this already!
}
}
}
2007-02-25 00:07:59 +00:00
void PageView : : slotToggleForms ( )
{
toggleFormWidgets ( ! d - > m_formsVisible ) ;
}
2007-10-18 22:09:49 +00:00
2013-06-03 20:46:41 +00:00
void PageView : : slotFormChanged ( int pageNumber )
2007-10-18 22:09:49 +00:00
{
2008-03-07 16:09:08 +00:00
if ( ! d - > refreshTimer ) {
d - > refreshTimer = new QTimer ( this ) ;
d - > refreshTimer - > setSingleShot ( true ) ;
2015-10-29 12:37:11 +00:00
connect ( d - > refreshTimer , & QTimer : : timeout , this , & PageView : : slotRefreshPage ) ;
2008-03-07 16:09:08 +00:00
}
2017-03-02 21:42:50 +00:00
d - > refreshPages < < pageNumber ;
2013-06-03 20:46:41 +00:00
int delay = 0 ;
if ( d - > m_formsVisible ) {
delay = 1000 ;
}
d - > refreshTimer - > start ( delay ) ;
2008-03-07 16:09:08 +00:00
}
void PageView : : slotRefreshPage ( )
{
2019-12-09 13:39:47 +00:00
for ( int req : qAsConst ( d - > refreshPages ) ) {
2019-12-19 22:18:31 +00:00
QTimer : : singleShot ( 0 , this , [ this , req ] { d - > document - > refreshPixmaps ( req ) ; } ) ;
2017-03-02 21:42:50 +00:00
}
d - > refreshPages . clear ( ) ;
2007-10-18 22:09:49 +00:00
}
2008-03-05 11:06:55 +00:00
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
2008-03-05 11:06:55 +00:00
void PageView : : slotSpeakDocument ( )
{
QString text ;
2019-03-26 22:37:30 +00:00
for ( const PageViewItem * item : qAsConst ( d - > items ) ) {
Okular : : RegularAreaRect * area = textSelectionForItem ( item ) ;
text . append ( item - > page ( ) - > text ( area ) ) ;
2008-03-05 11:06:55 +00:00
text . append ( ' \n ' ) ;
delete area ;
}
d - > tts ( ) - > say ( text ) ;
}
void PageView : : slotSpeakCurrentPage ( )
{
const int currentPage = d - > document - > viewport ( ) . pageNumber ;
PageViewItem * item = d - > items . at ( currentPage ) ;
Okular : : RegularAreaRect * area = textSelectionForItem ( item ) ;
const QString text = item - > page ( ) - > text ( area ) ;
delete area ;
d - > tts ( ) - > say ( text ) ;
}
2008-03-05 12:05:48 +00:00
void PageView : : slotStopSpeaks ( )
{
if ( ! d - > m_tts )
return ;
d - > m_tts - > stopAllSpeechs ( ) ;
}
2019-09-19 19:50:58 +00:00
void PageView : : slotPauseResumeSpeech ( )
{
if ( ! d - > m_tts )
return ;
d - > m_tts - > pauseResumeSpeech ( ) ;
}
2014-11-08 04:33:23 +00:00
# endif
2008-03-20 17:45:37 +00:00
void PageView : : slotAction ( Okular : : Action * action )
{
d - > document - > processAction ( action ) ;
}
2011-06-08 05:47:57 +00:00
void PageView : : externalKeyPressEvent ( QKeyEvent * e )
{
keyPressEvent ( e ) ;
}
2012-04-03 12:18:10 +00:00
void PageView : : slotProcessMovieAction ( const Okular : : MovieAction * action )
{
const Okular : : MovieAnnotation * movieAnnotation = action - > annotation ( ) ;
if ( ! movieAnnotation )
return ;
Okular : : Movie * movie = movieAnnotation - > movie ( ) ;
if ( ! movie )
return ;
const int currentPage = d - > document - > viewport ( ) . pageNumber ;
PageViewItem * item = d - > items . at ( currentPage ) ;
if ( ! item )
return ;
VideoWidget * vw = item - > videoWidgets ( ) . value ( movie ) ;
if ( ! vw )
return ;
vw - > show ( ) ;
switch ( action - > operation ( ) ) {
case Okular : : MovieAction : : Play :
vw - > stop ( ) ;
vw - > play ( ) ;
break ;
case Okular : : MovieAction : : Stop :
vw - > stop ( ) ;
break ;
case Okular : : MovieAction : : Pause :
vw - > pause ( ) ;
break ;
case Okular : : MovieAction : : Resume :
vw - > play ( ) ;
break ;
} ;
}
2012-09-27 12:15:58 +00:00
void PageView : : slotProcessRenditionAction ( const Okular : : RenditionAction * action )
{
Okular : : Movie * movie = action - > movie ( ) ;
if ( ! movie )
return ;
const int currentPage = d - > document - > viewport ( ) . pageNumber ;
PageViewItem * item = d - > items . at ( currentPage ) ;
if ( ! item )
return ;
VideoWidget * vw = item - > videoWidgets ( ) . value ( movie ) ;
if ( ! vw )
return ;
if ( action - > operation ( ) = = Okular : : RenditionAction : : None )
return ;
vw - > show ( ) ;
switch ( action - > operation ( ) ) {
case Okular : : RenditionAction : : Play :
vw - > stop ( ) ;
vw - > play ( ) ;
break ;
case Okular : : RenditionAction : : Stop :
vw - > stop ( ) ;
break ;
case Okular : : RenditionAction : : Pause :
vw - > pause ( ) ;
break ;
case Okular : : RenditionAction : : Resume :
vw - > play ( ) ;
break ;
2016-07-24 20:39:45 +00:00
default :
return ;
2012-09-27 12:15:58 +00:00
} ;
}
2018-06-26 11:05:25 +00:00
void PageView : : slotSetChangeColors ( bool active )
2013-10-26 09:40:41 +00:00
{
2018-06-26 11:05:25 +00:00
Okular : : SettingsCore : : setChangeColors ( active ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2013-10-26 09:40:41 +00:00
viewport ( ) - > update ( ) ;
}
2018-06-26 11:05:25 +00:00
void PageView : : slotToggleChangeColors ( )
{
slotSetChangeColors ( ! Okular : : SettingsCore : : changeColors ( ) ) ;
}
2015-03-16 23:20:11 +00:00
void PageView : : slotFitWindowToPage ( )
{
2019-01-09 23:28:49 +00:00
const PageViewItem * currentPageItem = nullptr ;
2015-03-16 23:20:11 +00:00
QSize viewportSize = viewport ( ) - > size ( ) ;
2019-12-09 13:39:47 +00:00
for ( const PageViewItem * pageItem : qAsConst ( d - > items ) ) {
2015-03-16 23:20:11 +00:00
if ( pageItem - > isVisible ( ) ) {
2019-01-09 23:28:49 +00:00
currentPageItem = pageItem ;
2015-03-16 23:20:11 +00:00
break ;
}
}
2019-01-09 23:28:49 +00:00
if ( ! currentPageItem )
return ;
const QSize pageSize = QSize ( currentPageItem - > uncroppedWidth ( ) + kcolWidthMargin , currentPageItem - > uncroppedHeight ( ) + krowHeightMargin ) ;
2015-03-16 23:20:11 +00:00
if ( verticalScrollBar ( ) - > isVisible ( ) )
viewportSize . setWidth ( viewportSize . width ( ) + verticalScrollBar ( ) - > width ( ) ) ;
if ( horizontalScrollBar ( ) - > isVisible ( ) )
viewportSize . setHeight ( viewportSize . height ( ) + horizontalScrollBar ( ) - > height ( ) ) ;
emit fitWindowToPage ( viewportSize , pageSize ) ;
}
Add action in Edit menu to select the text on current page
BUG: 358868
Test Plan: Click on "Select All Text on Current Page" entry in Edit menu to select the entire page. The selected text can then be copied via Edit menu item "Copy"
Reviewers: aacid, #vdg, ngraham
Reviewed By: #vdg, ngraham
Subscribers: yurchor, michaelweghorn, kde-doc-english, davidhurka, abetts, loh.tar, alexde, ngraham, okular-devel
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D18744
2019-04-21 23:06:54 +00:00
void PageView : : slotSelectPage ( )
{
textSelectionClear ( ) ;
const int currentPage = d - > document - > viewport ( ) . pageNumber ;
PageViewItem * item = d - > items . at ( currentPage ) ;
if ( item ) {
Okular : : RegularAreaRect * area = textSelectionForItem ( item ) ;
d - > pagesWithTextSelection . insert ( currentPage ) ;
d - > document - > setPageTextSelection ( currentPage , area , palette ( ) . color ( QPalette : : Active , QPalette : : Highlight ) ) ;
}
}
2019-01-05 22:30:25 +00:00
void PageView : : highlightSignatureFormWidget ( const Okular : : FormFieldSignature * form )
{
QVector < PageViewItem * > : : const_iterator dIt = d - > items . constBegin ( ) , dEnd = d - > items . constEnd ( ) ;
for ( ; dIt ! = dEnd ; + + dIt ) {
2019-12-09 13:39:47 +00:00
const QSet < FormWidgetIface * > fwi = ( * dIt ) - > formWidgets ( ) ;
for ( FormWidgetIface * fw : fwi ) {
2019-01-05 22:30:25 +00:00
if ( fw - > formField ( ) = = form ) {
SignatureEdit * widget = static_cast < SignatureEdit * > ( fw ) ;
widget - > setDummyMode ( true ) ;
QTimer : : singleShot ( 250 , this , [ = ] { widget - > setDummyMode ( false ) ; } ) ;
return ;
}
}
}
}
2004-10-29 21:52:06 +00:00
// END private SLOTS
2004-09-26 23:39:39 +00:00
2008-04-11 18:50:26 +00:00
/* kate: replace-tabs on; indent-width 4; */