diff --git a/ui/pageview.h b/ui/pageview.h --- a/ui/pageview.h +++ b/ui/pageview.h @@ -49,8 +49,38 @@ /** * @short The main view. Handles zoom and continuous mode.. oh, and page - * @short display of course :-) - * ... + * display of course :-) + * + * @par Coordinate Systems + * @parblock + * This is a scroll area, so it uses two straightforward coordinate systems: + * * Content area: An area on which PageViewItems are positioned. + * * Viewport area: The subarea of the contents area which is currently + * visible in the viewport. + * + * When scrolling, the content area does not change, + * but the content area coordinates of the viewport change. + * Points on the viewport area can be mapped to the content area, + * using the current scrollbar positions. + * @endparblock + * + * @par Zoom + * The viewport area is always a subarea of the content area. + * When zooming out, the viewport area keeps its size, so the content area can't get smaller. + * Instead, the size of the pages within the content area is changed. + * + * @par Layout + * @parblock + * The layout controls how pages are arranged in the content area. + * slotRelayoutPages() calculates the layout, + * and sets size and position of the PageViewItem objects. + * + * The cropped geometry of a PageViewItem determines + * how the visible part of the page is placed in the content area. + * For more information about page and layout geometry, see PageViewItem. + * @endparblock + * + * @see PageViewItem */ class PageView : public QAbstractScrollArea, public Okular::DocumentObserver, public Okular::View { @@ -66,14 +96,45 @@ enum ClearMode { ClearAllSelection, ClearOnlyDividers }; - // create actions that interact with this widget + /** + * Setup actions which do not change the visual representation of pages, + * i. e. actions which are save for PrintPreviewMode. + * + * This method is called in all EmbedModes. + */ void setupBaseActions( KActionCollection * collection ); + + /** + * Setup actions which can modify the view, + * but don't enable editing the document. + * + * This method is not called in PrintPreviewMode, + * where the view shall be as close to the printout as possible. + * + * @warning setupBaseActions() must have been called before this method. + */ void setupViewerActions( KActionCollection * collection ); + + /** + * Setup editing-like actions. + * + * This method is not called in non-editing modes + * (PrintPreviewMode, ViewerWidgetMode). + * + * @warning setupViewerActions() must have been called before this method. + */ void setupActions( KActionCollection * collection ); void updateActionState( bool docHasPages, bool docChanged, bool docHasFormWidgets ); - // misc methods (from RMB menu/children) + /** + * Returns true when calling fitPageWidth() will modify the page layout. + */ bool canFitPageWidth() const; + + /** + * Sets view mode to Single Page, zoom mode to Fit Width, + * and moves the viewport to page @p page. + */ void fitPageWidth( int page ); // keep in sync with pageviewutils void displayMessage( const QString & message, const QString & details = QString(), PageViewMessage::Icon icon=PageViewMessage::Info, int duration=-1 ); @@ -93,7 +154,24 @@ QVariant capability( ViewCapability capability ) const override; void setCapability( ViewCapability capability, const QVariant &option ) override; + /** + * Returns one selection area per page, using text-style selection. + * + * @param start Where to start the selection, in content area coordinates. + * @param end Where to end the selection, in content area coordinates. + * @param[out] firstpage The index of the first page, for which an area is returned. + */ QList< Okular::RegularAreaRect * > textSelections( const QPoint& start, const QPoint& end, int& firstpage ); + + /** + * Returns a text selection area, using text-style selection. + * + * @param item The page on which to select. + * @param startPoint Where to start the selection, in uncropped geometry coordinates of the PageViewItem. + * @param endPoint Where to end the selection, in uncropped geometry coordinates of the PageViewItem. + * + * @see PageViewItem + */ Okular::RegularAreaRect * textSelectionForItem( const PageViewItem * item, const QPoint & startPoint = QPoint(), const QPoint & endPoint = QPoint() ); void reparseConfig(); @@ -103,43 +181,110 @@ int contentAreaWidth() const; int contentAreaHeight() const; + + /** + * Returns the current position of the viewport area (top left corner) + * in the content area. + */ QPoint contentAreaPosition() const; + + /** + * Maps a point @p pos from viewport area coordinates to content area coordinates. + */ QPoint contentAreaPoint( const QPoint & pos ) const; + + /** + * Maps a point @p pos from viewport area coordinates to content area coordinates. + */ QPointF contentAreaPoint( const QPointF & pos ) const; bool areSourceLocationsShownGraphically() const; void setShowSourceLocationsGraphically(bool show); void setLastSourceLocationViewport( const Okular::DocumentViewport& vp ); void clearLastSourceLocationViewport(); + /** + * Updates the cursor shape according to the mouse mode and what is under the cursor. + */ void updateCursor(); void highlightSignatureFormWidget( const Okular::FormFieldSignature *form ); public Q_SLOTS: + /** + * Copies all currently selected text to the clipboard. + */ void copyTextSelection() const; + + /** + * Selects all text on all pages, and sets the selection highlight area. + */ void selectAll(); + /** + * Creates or rises an AnnotWindow to edit the + * annotation @p annotation on page @p pageNumber. + */ void openAnnotationWindow( Okular::Annotation *annotation, int pageNumber ); + + /** + * Updates all form widgets on all PageViewItems. + */ void reloadForms(); + /** + * Toggles the enabled state of the change colors feature. + */ void slotToggleChangeColors(); + + /** + * Enables or disables the change colors feature. + */ void slotSetChangeColors(bool active); + /** + * Clears existing text selections and selects all text on the current page. + */ void slotSelectPage(); Q_SIGNALS: - void rightClick( const Okular::Page *, const QPoint & ); + /** + * Emitted after a right click event. + * + * @param page The page on which the right click happened, nullptr if not on a page. + * @param point The global cursor position. + */ + void rightClick( const Okular::Page *page, const QPoint &point ); + + /** + * Emitted when the 'Back' button on the mouse is clicked. + */ void mouseBackButtonClick(); + + /** + * Emitted when the 'Forward' button on the mouse is clicked. + */ void mouseForwardButtonClick(); + void escPressed(); + + /** + * This is emitted when Fit Window to Page is triggered. + * + * @param pageViewPortSize The current size of the viewport, including scrollbars. + * @param pageSize The requested size of the new viewport, to fit the page. + */ void fitWindowToPage( const QSize& pageViewPortSize, const QSize& pageSize ); protected: bool event( QEvent * event ) override; void resizeEvent( QResizeEvent* ) override; + + /** + * Handles pinch zoom and rotation. + */ bool gestureEvent( QGestureEvent * e ); // mouse / keyboard events @@ -160,46 +305,164 @@ void scrollContentsBy( int dx, int dy ) override; private: - // draw background and items on the opened qpainter - void drawDocumentOnPainter( const QRect & pageViewRect, QPainter * p ); - // update item width and height using current zoom parameters + /** + * Draws parts of the PageViewItems, which are in @p pageViewRect, on @p painter. + * Background is filled with view background color. + * + * Top left corner of @p pageViewRect will be painted on (0, 0) of @p painter. + * + * @param pageViewRect The section of the content area, which shall be painted. + * @param painter The painter on which to paint. + */ + void drawDocumentOnPainter( const QRect & pageViewRect, QPainter * painter ); + + /** + * Updates size and cropping of @item, + * according to zoom and trim margins modes, + * and respecting layout size for zoomFit* modes. + * + * @param item The item to update. + * @param columnWidth Needed for zoomFit* modes. + * @param rowHeight Needed for zoomFit* modes. + */ void updateItemSize( PageViewItem * item, int columnWidth, int rowHeight ); - // return the widget placed on a certain point or 0 if clicking on empty space + + /** + * Returns the PageViewItem under the point (@p x, @p y) in content area coordinates, + * or nullptr if there is no item under the point. + */ PageViewItem * pickItemOnPoint( int x, int y ); // start / modify / clear selection rectangle void selectionStart( const QPoint & pos, const QColor & color, bool aboveAll = false ); void selectionClear( const ClearMode mode = ClearAllSelection ); void drawTableDividers(QPainter * screenPainter); void guessTableDividers(); // update either text or rectangle selection void updateSelection( const QPoint & pos ); - // compute the zoom factor value for FitWidth and FitPage mode + + /** + * Calculates which zoom factor @p mode would apply on the current page. + * + * @param mode ZoomFitWidth or ZoomFitPage. + * + * @return Zoom factor or 0 if not calculateable. + */ double zoomFactorFitMode( ZoomMode mode ); - // update internal zoom values and end in a slotRelayoutPages(); - void updateZoom( ZoomMode newZm ); - // update the text on the label using global zoom value or current page's one + + /** + * Calculates a new zoom factor and mode using @p newZoomMode, + * and relayouts the pages. + * + * @param newZoomMode If ZoomFixed, will use the current selection + * of the zoom selection action. + */ + void updateZoom( ZoomMode newZoomMode ); + + /** + * Rebuild the zoom factor items of the zoom select action and select + * the item of the current zoom. + * + * Call this when the zoom factor has changed. + */ void updateZoomText(); + + /** + * Clears the text selection highlight areas on all pages of the document. + */ void textSelectionClear(); - // updates cursor - void updateCursor( const QPoint &p ); + /** + * Updates the cursor shape according to the mouse mode and what is under the cursor. + * + * @param position The cursor position in content area coordinates. + */ + void updateCursor( const QPoint &position ); + + /** + * Move the magnifier widget to be centered on @p. + * If moved against the viewport edges, + * it will auto-scroll the content area in that direction. + * + * Call this when the cursor has moved while the magnifier is activated. + * + * @param position The cursor position in viewport area coordinates. + */ void moveMagnifier( const QPoint &p ); - void updateMagnifier( const QPoint &p ); + /** + * Update the position which the magnifier shall magnify. + * + * Call this when the cursor has moved while the magnifier is activated. + * + * @param position The cursor position in content area coordinates. + */ + void updateMagnifier( const QPoint &position ); + + /** + * Returns the theoretical number of columns of the current view mode. + * Might not always be accurate. + */ int viewColumns() const; + /** + * Centers the viewport on content area coordinate (@p cx, @p cy). + * + * @see scrollTo() + */ void center(int cx, int cy); + + /** + * Moves the viewport top left corner to content area coordinate (@p x, @p y). + * + * @see center() + */ void scrollTo( int x, int y ); + /** + * Sets visibility for all form widgets on all PageViewItems. + * If this hides a form widget with focus, this PageView gets focused. + */ void toggleFormWidgets( bool on ); + /** + * Resizes the content area to @p newSize and updates the scrollbars. + */ void resizeContentArea( const QSize & newSize ); + + /** + * Adjusts the page steps of the scrollbars to the viewport size. + */ void updatePageStep(); + /** + * Adds a submenu to @p menu, + * with actions to use the prefered web shortcuts for @p text. + */ void addWebShortcutsMenu( QMenu * menu, const QString & text ); + + /** + * Returns a context menu for the ObjectRect, to which @p eventPos points. + * If there is no ObjectRect under @p eventPos, returns nullptr. + * + * @param item The page on which the ObjectRect is expected. + * @param eventPos The position of the ObjectRect, in content area coordinates. + */ QMenu* createProcessLinkMenu( PageViewItem *item, const QPoint & eventPos ); - // used when selecting stuff, makes the view scroll as necessary to keep the mouse inside the view + + /** + * Starts auto-scrolling if @p pos is outside the viewport area. + * + * Use this when the user drags from inside the viewport area beyond its borders. + * + * @param pos A point in content area coordinates, that shall become visible. + */ void scrollPosIntoView( const QPoint & pos ); + + /** + * Returns the middle of viewport &p vp in content area coordinates. + * + * Undefined behaviour if @p vp does not point to a page in the current layout. + */ QPoint viewportToContentArea( const Okular::DocumentViewport & vp ) const; // called from slots to turn off trim modes mutually exclusive to id @@ -214,9 +477,27 @@ class PageViewPrivate * d; private Q_SLOTS: - // used to decouple the notifyViewportChanged calle + /** + * Updates the view when the document got a new viewport. + * + * Called trough DocumentObserver::notifyViewportChanged(). + * + * @param smoothMove Whether to animate the viewport change. + */ void slotRealNotifyViewportChanged(bool smoothMove); - // activated either directly or via queued connection on notifySetup + + /** + * Recalculates the page layout. + * + * Calcuclates which pages will be in the layout + * and moves them to their correct position in the layout. + * + * If Continuous view mode is enabled, all pages are in the layout. + * Otherwise, only one row of pages is in the layout. + * + * Call this when the viewport is resized, + * or when the page layout or zoom is changed. + */ void slotRelayoutPages(); // activated by the resize event delay timer void delayedResizeEvent(); @@ -233,7 +514,15 @@ // activated by left click timer void slotShowSizeAllCursor(); + /** + * Connected to web shortcuts menu actions. + * The connected action must have the URL from KUriFilterData set as data. + */ void slotHandleWebShortcutAction(); + + /** + * Shows the web shortcuts control module. + */ void slotConfigureWebShortcuts(); // connected to local actions (toolbar, menu, ..) @@ -273,9 +562,19 @@ #endif void slotAction( Okular::Action *action ); void externalKeyPressEvent( QKeyEvent *e ); + + /** + * Let this view forget about AnnotWindow @p window. + * + * Call this when the AnnotWindow is destroyed. + */ void slotAnnotationWindowDestroyed( QObject *window ); void slotProcessMovieAction( const Okular::MovieAction *action ); void slotProcessRenditionAction( const Okular::RenditionAction *action ); + + /** + * Emits fitWindowToPage, to tell the parent aplication to resize the window. + */ void slotFitWindowToPage(); }; diff --git a/ui/pageview.cpp b/ui/pageview.cpp --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -102,9 +102,12 @@ static const float 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 }; -static inline double normClamp( double value, double def ) +/** + * Returns @p value if in [0, 1], @p defaultValue otherwise. + */ +static inline double normClamp( double value, double defaultValue ) { - return ( value < 0.0 || value > 1.0 ) ? def : value; + return ( value < 0.0 || value > 1.0 ) ? defaultValue : value; } struct TableSelectionPart { @@ -130,6 +133,9 @@ #ifdef HAVE_SPEECH OkularTTS* tts(); #endif + /** + * Returns all currently selected text. + */ QString selectedText() const; // the document, pageviewItems and the 'visible cache' @@ -612,7 +618,6 @@ connect( aToggleChangeColors, &QAction::triggered, this, &PageView::slotToggleChangeColors ); } -// WARNING: 'setupViewerActions' must have been called before this method void PageView::setupActions( KActionCollection * ac ) { d->actionCollection = ac; @@ -1355,7 +1360,6 @@ void PageView::notifyPageChanged( int pageNumber, int changedFlags ) { - // only handle pixmap / highlight changes notifies if ( changedFlags & DocumentObserver::Bookmark ) return; @@ -1453,7 +1457,7 @@ if ( abs( visibleItem->pageNumber() - pageNumber ) <= 1 ) return false; } - // if hidden premit unloading + // if hidden permit unloading return true; } @@ -3751,13 +3755,19 @@ // 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); - else d->dragScrollVector.setX(0); + 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); + else + d->dragScrollVector.setX(0); - 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); - else d->dragScrollVector.setY(0); + 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); + else + d->dragScrollVector.setY(0); if (d->dragScrollVector != QPoint(0, 0)) { @@ -3831,6 +3841,13 @@ } } +/** + * Normalizes a point from a rotated reference area. + * + * @param rotated The point in absolute coordinates on the rotated reference area. + * @param rect The rotated reference area. + * @param rotation The rotation of the reference area. This function does the reverse rotation. + */ static Okular::NormalizedPoint rotateInNormRect( const QPoint &rotated, const QRect &rect, Okular::Rotation rotation ) { Okular::NormalizedPoint ret; @@ -3912,17 +3929,25 @@ const int pageCount = d->items.count(); if ( pageCount == 0 ) return 0; + + // Determine how many columns to fit. 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(); + + // Calculate desired page display size. const double colWidth = viewport()->width() / nCols - kcolWidthMargin; const double rowHeight = viewport()->height() - krowHeightMargin; + + // Get the size of the current page. const PageViewItem * currentItem = d->items[ qMax( 0, (int)d->document->currentPage()) ]; // prevent segmentation fault when opening a new document; if ( !currentItem ) return 0; const Okular::Page * okularPage = currentItem->page(); const double width = okularPage->width(), height = okularPage->height(); + + // Calculate the zoom factor. if ( mode == ZoomFitWidth ) return (double) colWidth / width; if ( mode == ZoomFitPage ) @@ -3946,6 +3971,7 @@ newZoomMode = ZoomFitAuto; } + // Calculate new zoom factor. float newFactor = d->zoomFactor; QAction * checkedZoomAction = nullptr; switch ( newZoomMode ) @@ -4021,6 +4047,7 @@ if ( newFactor < 0.1 ) newFactor = 0.1; + // Apply new zoom mode and factor. if ( newZoomMode != d->zoomMode || (newZoomMode == ZoomFixed && newFactor != d->zoomFactor ) ) { // rebuild layout and update the whole viewport @@ -4211,6 +4238,7 @@ const int w = d->magnifierView->width() * 0.5; const int h = d->magnifierView->height() * 0.5; + // Get top left corner of magnifier. int x = p.x() - w; int y = p.y() - h; @@ -4249,7 +4277,7 @@ d->magnifierView->move(x, y); } -void PageView::updateMagnifier( const QPoint& p ) // scaled point +void PageView::updateMagnifier( const QPoint& p ) { /* translate mouse coordinates to page coordinates and inform the magnifier of the situation */ PageViewItem *item = pickItemOnPoint(p.x(), p.y()); @@ -4263,13 +4291,16 @@ int PageView::viewColumns() const { int vm = Okular::Settings::viewMode(); - if (vm == Okular::Settings::EnumViewMode::Single) return 1; + if (vm == Okular::Settings::EnumViewMode::Single) + return 1; else if (vm == Okular::Settings::EnumViewMode::Facing || - vm == Okular::Settings::EnumViewMode::FacingFirstCentered) return 2; + vm == Okular::Settings::EnumViewMode::FacingFirstCentered) + return 2; else if (vm == Okular::Settings::EnumViewMode::Summary && d->document->pages() < Okular::Settings::viewColumns() ) - return d->document->pages(); - else return Okular::Settings::viewColumns(); + return d->document->pages(); + else + return Okular::Settings::viewColumns(); } void PageView::center(int cx, int cy) @@ -4552,7 +4583,7 @@ { const bool reallyDoCenterFirst = item->pageNumber() == 0 && centerFirstPage; const bool reallyDoCenterLast = item->pageNumber() == pageCount - 1 && centerLastPage; - int actualX = 0; + int actualX; if ( reallyDoCenterFirst || reallyDoCenterLast ) { // page is centered across entire viewport diff --git a/ui/pageviewutils.h b/ui/pageviewutils.h --- a/ui/pageviewutils.h +++ b/ui/pageviewutils.h @@ -33,10 +33,39 @@ } /** - * @short PageViewItem represents graphically a page into the PageView. + * @short PageViewItem represents a Page, to be used in a PageView. * - * It has methods for settings Item's geometry and other visual properties such - * as the individual zoom factor. + * @par Geometry + * @parblock + * PageViewItem stores geometry information to position the page in + * the content area of the PageView. + * * The uncropped geometry describing the whole page, + * * The cropped geometry describing the visible part of the page after e. g. Trim Margins, + * * The used zoom factor, + * * The used crop rectangle. + * + * The cropped geometry describes the part of the page, + * which is used for the layout of the PageView. + * If Trim Margins or Trim to Selection is used, + * the cropped geometry does not contain the trimmed-away margins. + * + * The uncropped geometry describes the whole page. + * Various objects on the page (e. g. TextEntity) are positioned in normalized coordinates. + * To convert normalized coordinates to content area coordinates for PageView, + * the uncropped geometry is needed as reference area. + * + * @note + * For the conversion from normalized coordinates to content area coordinates, + * the rotation of the page is needed, but rotation is not covered by this class. + * (Uncropped geometry, cropped geometry, and the crop rectange are only valid + * for the current rotation of the page, which is sufficient for layouting.) + * @endparblock + * + * @par Other Properties + * * The visibility of the page, + * * Lists of interactive widgets on the page, + * * Which types of widgets are visible, + * * A pointer to the Page itself. */ class PageViewItem { @@ -47,40 +76,82 @@ PageViewItem(const PageViewItem &) = delete; PageViewItem &operator=(const PageViewItem &) = delete; + /** + * Returns the represented Page. + */ const Okular::Page * page() const; + + /** + * Returns the number of the represented Page. + * First page has number 0. + * Provided for convenience. + */ int pageNumber() const; + double zoomFactor() const; bool isVisible() const; QSet& formWidgets(); QHash< Okular::Movie *, VideoWidget * >& videoWidgets(); - /* The page is cropped as follows: */ + /** + * Describes the cropped geometry relative to the uncropped geometry. + */ const Okular::NormalizedRect & crop() const; - /* Real geometry into which the cropped page is rendered: */ const QRect& croppedGeometry() const; int croppedWidth() const; int croppedHeight() const; - /* "Uncropped" geometry: - * If the whole page was rendered into the uncropped geometry then the - * cropped page would be rendered into the real geometry. - * (Hence, uncropped always contains cropped, and they are equal only if - * the page is uncropped.) This is just for convenience in calculations. - */ const QRect& uncroppedGeometry() const; int uncroppedWidth() const; int uncroppedHeight() const; - /* Convert absolute geometry coordinates to normalized [0,1] page coordinates: */ + /** + * Converts x coordinate from PageView content area coordinates to + * the normalized coordinate system of the page, not covering page rotation. + */ double absToPageX(double absX) const; + + /** + * Converts y coordinate from PageView content area coordinates to + * the normalized coordinate system of the page, not covering page rotation. + */ double absToPageY(double absY) const; + /** + * Sets the size of the page. + * + * (Uncropped geometry will be calculated from @p width, @p height, and @p crop.) + * + * @param width Cropped width. + * @param height Cropped height. + * @param zoom The zoom factor which yields these dimensions. + * @param crop Describes the cropped geometry relative to the uncropped geometry. + */ void setWHZC( int w, int h, double zoom, const Okular::NormalizedRect & c ); + + /** + * Sets the position of the page in the PageView layout. + * + * @p x and @p y describe the top left corner of the cropped geometry, + * in the PageView coordinate system. + * Uncropped geometry is updated automatically. + */ void moveTo( int x, int y ); void setVisible( bool visible ); void invalidate(); + + /** + * Sets all form widgets on this PageViewItem visible or invisible, + * provided this PageViewItem is visible. + * + * @return True, if some form widgets had focus. + */ bool setFormWidgetsVisible( bool visible ); + + /** + * Updates the visibility state of all form widgets of this PageViewItem. + */ void reloadFormWidgetsState(); private: @@ -100,7 +171,7 @@ * @short A widget that displays messages in the top-left corner. * * This is a widget with thin border and rounded corners that displays a given - * text along as an icon. It's meant to be used for displaying messages to the + * text and icon. It's meant to be used for displaying messages to the * user by placing this above other widgets. */ class PageViewMessage : public QWidget