mirror of
https://invent.kde.org/graphics/okular
synced 2024-08-24 18:35:37 +00:00
![Tobias Deiminger](/assets/img/avatar_default.png)
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
178 lines
6.8 KiB
C++
178 lines
6.8 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2017 by Tobias Deiminger <haxtibal@t-online.de> *
|
|
* Copyright (C) 2004-2005 by Enrico Ros <eros.kde@email.it> *
|
|
* Copyright (C) 2004-2006 by Albert Astals Cid <aacid@kde.org> *
|
|
* 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 *
|
|
* *
|
|
* With portions of code from kpdf/kpdf_pagewidget.cc by: *
|
|
* 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> *
|
|
* Copyright (C) 2011 by Jiri Baum - NICTA <jiri@baum.com.au> *
|
|
* *
|
|
* 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. *
|
|
***************************************************************************/
|
|
|
|
#ifndef _OKULAR_PAGEVIEWMOUSEANNOTATION_H_
|
|
#define _OKULAR_PAGEVIEWMOUSEANNOTATION_H_
|
|
|
|
#include <qobject.h>
|
|
|
|
#include "pageviewutils.h"
|
|
#include "core/annotations.h"
|
|
|
|
class QHelpEvent;
|
|
class QPainter;
|
|
class QPoint;
|
|
class PageView;
|
|
class PageViewItem;
|
|
class AnnotationDescription;
|
|
|
|
namespace Okular
|
|
{
|
|
class Document;
|
|
}
|
|
|
|
/* This class shall help to keep data for one annotation consistent. */
|
|
class AnnotationDescription
|
|
{
|
|
public:
|
|
AnnotationDescription()
|
|
: annotation( nullptr ), pageViewItem( nullptr ), pageNumber( -1 ) {}
|
|
AnnotationDescription( PageViewItem * newPageViewItem, const QPoint& eventPos );
|
|
bool isValid() const;
|
|
bool isContainedInPage( const Okular::Document * document, int pageNumber ) const;
|
|
void invalidate();
|
|
bool operator==( const AnnotationDescription & rhs ) const
|
|
{
|
|
return ( annotation == rhs.annotation );
|
|
}
|
|
Okular::Annotation * annotation;
|
|
PageViewItem * pageViewItem;
|
|
int pageNumber;
|
|
};
|
|
|
|
/**
|
|
* @short Handle UI for annotation interactions, like moving, resizing and triggering actions.
|
|
*
|
|
* An object of this class tracks which annotation is currently under the mouse cursor.
|
|
* Some annotation types can be focused in order to move or resize them.
|
|
* State is determined from mouse and keyboard events, which are forwarded from the parent PageView object.
|
|
* Move and resize actions are dispatched to the Document object.
|
|
*/
|
|
class MouseAnnotation : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
MouseAnnotation( PageView * parent, Okular::Document * document );
|
|
~MouseAnnotation();
|
|
|
|
/* Process a mouse press event. eventPos: Mouse position in content area coordinates. */
|
|
void routeMousePressEvent( PageViewItem * pageViewItem, const QPoint & eventPos );
|
|
|
|
/* Process a mouse release event. */
|
|
void routeMouseReleaseEvent();
|
|
|
|
/* Process a mouse move event. eventPos: Mouse position in content area coordinates. */
|
|
void routeMouseMoveEvent( PageViewItem * pageViewItem, const QPoint & eventPos, bool leftButtonPressed );
|
|
|
|
/* Process a key event. */
|
|
void routeKeyPressEvent( const QKeyEvent * e );
|
|
|
|
/* Process a tooltip event. eventPos: Mouse position in content area coordinates. */
|
|
void routeTooltipEvent( const QHelpEvent * helpEvent );
|
|
|
|
/* Process a paint event. */
|
|
void routePaint( QPainter * painter, const QRect & paintRect );
|
|
|
|
/* Cancel the current selection or action, if any. */
|
|
void cancel();
|
|
|
|
/* Reset to initial state. Cancel current action and relinquish references to PageViewItem widgets. */
|
|
void reset();
|
|
|
|
Okular::Annotation * annotation() const;
|
|
|
|
/* Return true, if MouseAnnotation demands control for a mouse click on the current cursor position. */
|
|
bool isMouseOver() const;
|
|
|
|
bool isActive() const;
|
|
|
|
bool isFocused() const;
|
|
|
|
bool isMoved() const;
|
|
|
|
bool isResized() const;
|
|
|
|
bool isModified() const;
|
|
|
|
Qt::CursorShape cursor() const;
|
|
|
|
/* Forward DocumentObserver::notifyPageChanged to this method. */
|
|
void notifyAnnotationChanged( int pageNumber );
|
|
|
|
/* Forward DocumentObserver::notifySetup to this method. */
|
|
void updateAnnotationPointers();
|
|
|
|
enum MouseAnnotationState {
|
|
StateInactive,
|
|
StateFocused,
|
|
StateMoving,
|
|
StateResizing
|
|
};
|
|
|
|
enum ResizeHandleFlag {
|
|
RH_None = 0,
|
|
RH_Top = 1,
|
|
RH_Right = 2,
|
|
RH_Bottom = 4,
|
|
RH_Left = 8,
|
|
RH_TopLeft = RH_Top | RH_Left,
|
|
RH_BottomLeft = RH_Bottom | RH_Left,
|
|
RH_TopRight = RH_Top | RH_Right,
|
|
RH_BottomRight = RH_Bottom | RH_Right,
|
|
RH_Content = 16,
|
|
RH_AllHandles = RH_Top | RH_Right | RH_Bottom | RH_Left
|
|
};
|
|
Q_DECLARE_FLAGS( ResizeHandle, ResizeHandleFlag )
|
|
|
|
private:
|
|
void setState( MouseAnnotationState state, const AnnotationDescription & ad );
|
|
QRect getFullBoundingRect( const AnnotationDescription & ad ) const;
|
|
void performCommand( const QPoint & newPos );
|
|
void finishCommand();
|
|
void updateViewport( const AnnotationDescription & ad ) const;
|
|
ResizeHandle getHandleAt( const QPoint & eventPos, const AnnotationDescription & ad ) const;
|
|
QRect getHandleRect( ResizeHandle handle, const AnnotationDescription & ad ) const;
|
|
static void handleToAdjust( const QPointF & dIn, QPointF & dOut1, QPointF & dOut2, MouseAnnotation::ResizeHandle handle, Okular::Rotation rotation );
|
|
static QPointF rotateInRect( const QPointF & rotated, Okular::Rotation rotation );
|
|
static ResizeHandle rotateHandle( ResizeHandle handle, Okular::Rotation rotation );
|
|
void processAction( const AnnotationDescription& ad );
|
|
|
|
/* We often have to delegate to the document model and our parent widget. */
|
|
Okular::Document * m_document;
|
|
PageView * m_pageView;
|
|
|
|
/* Remember which annotation is currently focused/modified. */
|
|
MouseAnnotationState m_state;
|
|
MouseAnnotation::ResizeHandle m_handle;
|
|
AnnotationDescription m_focusedAnnotation;
|
|
|
|
/* Mouse tracking, always kept up to date with the latest mouse position and annotation under mouse cursor. */
|
|
AnnotationDescription m_mouseOverAnnotation;
|
|
QPoint m_mousePosition; // in page view item coordinates
|
|
|
|
QList<ResizeHandle> m_resizeHandleList;
|
|
};
|
|
|
|
#endif
|