diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,7 +385,7 @@ ui/thumbnaillist.cpp ui/toc.cpp ui/tocmodel.cpp - ui/toolaction.cpp + ui/toggleactionmenu.cpp ui/videowidget.cpp ui/layers.cpp ui/signatureguiutils.cpp diff --git a/conf/preferencesdialog.h b/conf/preferencesdialog.h --- a/conf/preferencesdialog.h +++ b/conf/preferencesdialog.h @@ -32,6 +32,7 @@ public: PreferencesDialog( QWidget * parent, KConfigSkeleton * config, Okular::EmbedMode embedMode ); + void switchToAccessibilityPage(); void switchToAnnotationsPage(); protected: @@ -52,6 +53,7 @@ DlgDebug * m_debug; #endif + KPageWidgetItem * m_accessibilityPage; KPageWidgetItem * m_annotationsPage; }; diff --git a/conf/preferencesdialog.cpp b/conf/preferencesdialog.cpp --- a/conf/preferencesdialog.cpp +++ b/conf/preferencesdialog.cpp @@ -29,6 +29,7 @@ m_general = new DlgGeneral( this, embedMode ); m_performance = new DlgPerformance( this ); m_accessibility = new DlgAccessibility( this ); + m_accessibilityPage = nullptr; m_presentation = nullptr; m_annotations = nullptr; m_annotationsPage = nullptr; @@ -38,7 +39,7 @@ #endif addPage( m_general, i18n("General"), QStringLiteral("okular"), i18n("General Options") ); - addPage( m_accessibility, i18n("Accessibility"), QStringLiteral("preferences-desktop-accessibility"), i18n("Accessibility Reading Aids") ); + m_accessibilityPage = addPage( m_accessibility, i18n("Accessibility"), QStringLiteral("preferences-desktop-accessibility"), i18n("Accessibility Reading Aids") ); addPage( m_performance, i18n("Performance"), QStringLiteral("preferences-system-performance"), i18n("Performance Tuning") ); if( embedMode == Okular::ViewerWidgetMode ) { @@ -61,6 +62,12 @@ setHelp(QStringLiteral("configure"), QStringLiteral("okular")); } +void PreferencesDialog::switchToAccessibilityPage() +{ + if ( m_accessibilityPage ) + setCurrentPage( m_accessibilityPage ); +} + void PreferencesDialog::switchToAnnotationsPage() { if ( m_annotationsPage ) diff --git a/part.h b/part.h --- a/part.h +++ b/part.h @@ -252,6 +252,8 @@ void moveSplitter( const int sideWidgetSize ); + void slotAccessibilityPreferences(); + private: bool aboutToShowContextMenu(QMenu *menu, QAction *action, QMenu *contextMenu); void showMenu(const Okular::Page *page, const QPoint &point, const QString &bookmarkTitle = QString(), const Okular::DocumentViewport &vp = DocumentViewport(), bool showTOCActions = false); diff --git a/part.cpp b/part.cpp --- a/part.cpp +++ b/part.cpp @@ -623,7 +623,7 @@ if ( m_embedMode != PrintPreviewMode ) { // now set up actions that are required for all remaining modes - m_pageView->setupViewerActions( actionCollection() ); + m_pageView->setupViewerActions( actionCollection(), this ); // and if we are not in viewer mode, we want the full GUI if ( m_embedMode != ViewerWidgetMode ) { @@ -2945,6 +2945,17 @@ m_pageView->slotSetChangeColors(active); } +void Part::slotAccessibilityPreferences() +{ + // Create dialog + PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Okular::Settings::self(), m_embedMode ); + dialog->setAttribute( Qt::WA_DeleteOnClose ); + + // Show it + dialog->switchToAccessibilityPage(); + dialog->show(); +} + void Part::slotAnnotationPreferences() { // Create dialog diff --git a/ui/pageview.h b/ui/pageview.h --- a/ui/pageview.h +++ b/ui/pageview.h @@ -34,6 +34,7 @@ namespace Okular { class Action; +class Part; class Document; class DocumentViewport; class FormFieldSignature; @@ -68,7 +69,7 @@ // create actions that interact with this widget void setupBaseActions( KActionCollection * collection ); - void setupViewerActions( KActionCollection * collection ); + void setupViewerActions( KActionCollection * collection, Okular::Part * part ); void setupActions( KActionCollection * collection ); void updateActionState( bool docHasPages, bool docChanged, bool docHasFormWidgets ); @@ -210,6 +211,13 @@ void createAnnotationsVideoWidgets(PageViewItem *item, const QLinkedList< Okular::Annotation * > &annotations); + /** + * Updates the default action and the checked states of the color mode menu. + * + * Call this when the color mode was changed or Change Colors was toggled. + */ + void updateColorModeMenu(); + // don't want to expose classes in here class PageViewPrivate * d; @@ -263,6 +271,14 @@ void slotPageSizes( int ); void slotTrimMarginsToggled( bool ); void slotTrimToSelectionToggled( bool ); + + /** + * Sets the color mode (render mode) to the one represented by @p action. + * + * If @p action represents the current mode, toggles the Change Colors feature. + */ + void slotColorModeActionTriggered(QAction * action); + void slotToggleForms(); void slotFormChanged( int pageNumber ); void slotRefreshPage(); diff --git a/ui/pageview.cpp b/ui/pageview.cpp --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -63,6 +63,7 @@ // local includes #include "debug_ui.h" +#include "part.h" #include "formwidgets.h" #include "pageviewutils.h" #include "pagepainter.h" @@ -73,7 +74,7 @@ #include "pageviewannotator.h" #include "pageviewmouseannotation.h" #include "priorities.h" -#include "toolaction.h" +#include "toggleactionmenu.h" #include "okmenutitle.h" #ifdef HAVE_SPEECH #include "tts.h" @@ -229,6 +230,9 @@ KToggleAction * aZoomAutoFit; KActionMenu * aViewMode; KToggleAction * aViewContinuous; + ToggleActionMenu * aColorModeMenu; + QActionGroup * colorModeActions; + QAction * aColorModeNormal; QAction * aPrevAction; QAction * aToggleForms; QAction * aSpeakDoc; @@ -488,7 +492,7 @@ d->aZoomActual->setText(i18n("Zoom to 100%")); } -void PageView::setupViewerActions( KActionCollection * ac ) +void PageView::setupViewerActions( KActionCollection * ac, Okular::Part * part ) { d->actionCollection = ac; @@ -607,9 +611,59 @@ mz->setActionGroup( d->mouseModeActionGroup ); mz->setChecked( Okular::Settings::mouseMode() == Okular::Settings::EnumMouseMode::Zoom ); - QAction * aToggleChangeColors = new QAction(i18n("&Toggle Change Colors"), this); - ac->addAction(QStringLiteral("toggle_change_colors"), aToggleChangeColors ); - connect( aToggleChangeColors, &QAction::triggered, this, &PageView::slotToggleChangeColors ); + // Color Mode action menu + // The toolbar button will always show the last selected Change Colors mode, + // which is determined by Okular::SettingsCore::renderMode(). + d->aColorModeMenu = new ToggleActionMenu( QIcon::fromTheme( QStringLiteral("color-management") ), i18nc("@title:menu", "&Color Mode" ), this ); + // Add the menu to the action collection, so it can be plugged into the tool bar. + // It will not confuse the Configure Shortcuts dialog, because KActionMenu does not accept a shortcut. + ac->addAction( QStringLiteral( "color_mode_menu"), d->aColorModeMenu ); + d->colorModeActions = new QActionGroup( this ); + + // Add color mode Normal Colors action. + d->aColorModeNormal = new QAction( i18nc( "@item:inmenu color mode", "&Normal Colors" ), this ); + d->aColorModeNormal->setCheckable( true ); + ac->addAction( QStringLiteral( "color_mode_normal"), d->aColorModeNormal ); + d->aColorModeMenu->addAction( d->aColorModeNormal ); + d->colorModeActions->addAction( d->aColorModeNormal ); + + // Add other color mode actions. + auto addColorMode = [=] ( QAction * a, QString name, Okular::SettingsCore::EnumRenderMode::type id ) { + a->setCheckable( true ); + a->setData( int( id ) ); + d->aColorModeMenu->addAction( a ); + ac->addAction( name, a ); + d->colorModeActions->addAction( a ); + }; + QAction * tmpAction = new QAction( i18nc( "@item:inmenu color mode", "&Invert Colors" ), this ); + addColorMode( tmpAction, + "color_mode_inverted", Okular::SettingsCore::EnumRenderMode::Inverted ); + connect( tmpAction, &QAction::triggered, [=] (bool checked) { qDebug() << "color_mode_inverted triggered, now" << checked; } ); + tmpAction = new QAction( i18nc( "@item:inmenu color mode", "Change &Paper Color" ), this ); + addColorMode( tmpAction, + "color_mode_paper", Okular::SettingsCore::EnumRenderMode::Paper ); + connect( tmpAction, &QAction::triggered, [=] (bool checked) { qDebug() << "color_mode_paper triggered, now" << checked; } ); + tmpAction = new QAction( i18nc( "@item:inmenu color mode", "Change &Dark && Light Colors" ), this ); + addColorMode( tmpAction, + "color_mode_recolor", Okular::SettingsCore::EnumRenderMode::Recolor ); + connect( tmpAction, &QAction::triggered, [=] (bool checked) { qDebug() << "color_mode_recolor triggered, now" << checked; } ); + tmpAction = new QAction( i18nc( "@item:inmenu color mode", "Convert to &Black && White" ), this ); + addColorMode( tmpAction, + "color_mode_black_white", Okular::SettingsCore::EnumRenderMode::BlackWhite ); + connect( tmpAction, &QAction::triggered, [=] (bool checked) { qDebug() << "color_mode_black_white triggered, now" << checked; } ); + + connect( d->colorModeActions, &QActionGroup::triggered, + this, &PageView::slotColorModeActionTriggered ); + + // Add Configure Color Modes action. + d->aColorModeMenu->addSeparator(); + QAction * aConfigure = new QAction( QIcon::fromTheme( QStringLiteral("configure") ), + i18nc( "@item:inmenu color mode", "C&onfigure Color Modes..." ), + this ); + d->aColorModeMenu->addAction( aConfigure ); + connect( aConfigure, &QAction::triggered, part, &Okular::Part::slotAccessibilityPreferences ); + + updateColorModeMenu(); } // WARNING: 'setupViewerActions' must have been called before this method @@ -654,18 +708,33 @@ d->aMouseMagnifier->setActionGroup( d->mouseModeActionGroup ); d->aMouseMagnifier->setChecked( Okular::Settings::mouseMode() == Okular::Settings::EnumMouseMode::Magnifier ); + // Mouse-Mode action menu + ToggleActionMenu *mouseModeMenu = new ToggleActionMenu( this ); + mouseModeMenu->addAction( d->aMouseSelect ); + mouseModeMenu->addAction( d->aMouseTextSelect ); + mouseModeMenu->addAction( d->aMouseTableSelect ); + mouseModeMenu->setText( i18nc( "@action", "Selection Tools" ) ); + ac->addAction( QStringLiteral( "mouse_selecttools" ), mouseModeMenu ); + connect( mouseModeMenu->menu(), &QMenu::triggered, + mouseModeMenu, &ToggleActionMenu::setDefaultAction ); + + // Use the current mouse mode action as default action, or Text Selection by default. + QAction* enabledMouseModeAction = d->mouseModeActionGroup->checkedAction(); + if ( enabledMouseModeAction && mouseModeMenu->menu()->actions().contains( enabledMouseModeAction ) ) + { + mouseModeMenu->setDefaultAction( enabledMouseModeAction ); + } + else + { + mouseModeMenu->setDefaultAction( d->aMouseTextSelect ); + } + d->aToggleAnnotator = new KToggleAction(QIcon::fromTheme( QStringLiteral("draw-freehand") ), i18n("&Review"), this); ac->addAction(QStringLiteral("mouse_toggle_annotate"), d->aToggleAnnotator ); d->aToggleAnnotator->setCheckable( true ); connect( d->aToggleAnnotator, &QAction::toggled, this, &PageView::slotToggleAnnotator ); ac->setDefaultShortcut(d->aToggleAnnotator, Qt::Key_F6); - ToolAction *ta = new ToolAction( this ); - ac->addAction( QStringLiteral("mouse_selecttools"), ta ); - ta->addAction( d->aMouseTextSelect ); - ta->addAction( d->aMouseSelect ); - ta->addAction( d->aMouseTableSelect ); - // speak actions #ifdef HAVE_SPEECH d->aSpeakDoc = new QAction( QIcon::fromTheme( QStringLiteral("text-speak") ), i18n( "Speak Whole Document" ), this ); @@ -1177,6 +1246,9 @@ if ( d->aViewContinuous ) d->aViewContinuous->setEnabled( haspages ); + if ( d->aColorModeMenu ) + d->aColorModeMenu->setEnabled( haspages ); + if ( d->aZoomFitWidth ) d->aZoomFitWidth->setEnabled( haspages ); if ( d->aZoomFitPage ) @@ -5504,13 +5576,52 @@ Okular::SettingsCore::setChangeColors(active); Okular::Settings::self()->save(); viewport()->update(); + updateColorModeMenu(); } void PageView::slotToggleChangeColors() { slotSetChangeColors( !Okular::SettingsCore::changeColors() ); } +void PageView::slotColorModeActionTriggered( QAction * action ) +{ + const int newRenderMode = action->data().toInt(); + if ( Okular::SettingsCore::renderMode() == newRenderMode || action == d->aColorModeNormal ) + { + slotToggleChangeColors(); + } + else + { + Okular::SettingsCore::setRenderMode( newRenderMode ); + slotSetChangeColors( true ); + updateColorModeMenu(); + } +} + +void PageView::updateColorModeMenu() +{ + // Check the current color mode. + const int rm = Okular::SettingsCore::renderMode(); + for ( QAction * a : d->colorModeActions->actions() ) + { + if ( a == d->aColorModeNormal ) + { + continue; + } + + if ( a->data().toInt() == rm ) + { + a->setChecked( true ); + d->aColorModeMenu->setDefaultAction( a ); + break; + } + } + + // If Change Colors is disabled, check Normal Colors instead. + d->aColorModeNormal->setChecked( !Okular::SettingsCore::changeColors() ); +} + void PageView::slotFitWindowToPage() { const PageViewItem *currentPageItem = nullptr; diff --git a/ui/toggleactionmenu.h b/ui/toggleactionmenu.h new file mode 100644 --- /dev/null +++ b/ui/toggleactionmenu.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2019 by David Hurka * + * * + * Inspired by and replacing toolaction.h by: * + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * 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 TOGGLEACTIONMENU_H +#define TOGGLEACTIONMENU_H + +#include +#include +#include + +/** + * @brief A KActionMenu, with allows to set the default action of its toolbar buttons. + * + * Usually, a KActionMenu creates toolbar buttons which reflect its own action properties + * (icon, text, tooltip, checked state,...), as it is a QAction itself. + * ToggleActionMenu will use its own action properties only when plugged as submenu in another menu. + * But the default action of the toolbar buttons can easily be changed with the slot setDefaultAction(). + * + * Naming: The user can *Toggle* the checked state of an *Action* by directly clicking the toolbar button, + * but can also open a *Menu*. + * + * @par Intention + * Setting the default action of the toolbar button can be useful for: + * * Providing the most propably needed entry of a menu directly on the menu button. + * * Showing the last used menu entry on the menu button, including its checked state. + * The advantage is that the user often does not need to open the menu, + * and that the toolbar button shows additional information + * like checked state or the user's last selection. + * + * This shall replace the former ToolAction in Okular, + * while beeing flexible enough for other (planned) action menus. + */ +class ToggleActionMenu : public KActionMenu +{ + Q_OBJECT + +public: + explicit ToggleActionMenu( QWidget *parent ); + ToggleActionMenu( const QString &text, QWidget * parent ); + /** + * These are the usual constructors for KActionMenu. + * + * @note + * @p text and @p icon are used only if this menu is a submenu in another menu. + * To set the appearance of the toolbar buttons, use setDefaultAction. + */ + ToggleActionMenu( const QIcon &icon, const QString &text, QWidget *parent ); + + QWidget *createWidget( QWidget *parent ) override; + + /** + * Returns the current default action of the toolbar buttons. + */ + QAction *defaultAction(); + +public slots: + /** + * Sets the default action of the toolbar buttons. + * + * This action will be triggered by clicking directly on the toolbar buttons. + * It will also set the text, icon, checked state, etc. of the toolbar buttons. + * + * @note + * The action will not be added to the menu, + * it usually makes sense to addAction() it before to setDefaultAction() it. + */ + void setDefaultAction( QAction *action ); + +private: + QAction *m_defaultAction; + QList< QPointer< QToolButton > > m_buttons; +}; + +#endif // TOGGLEACTIONMENU_H diff --git a/ui/toggleactionmenu.cpp b/ui/toggleactionmenu.cpp new file mode 100644 --- /dev/null +++ b/ui/toggleactionmenu.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2019 by David Hurka * + * * + * Inspired by and replacing toolaction.h by: * + * Copyright (C) 2004-2006 by Albert Astals Cid * + * * + * 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. * + ***************************************************************************/ + +#include "toggleactionmenu.h" + +#include + +ToggleActionMenu::ToggleActionMenu( QWidget * parent ) + : KActionMenu( parent ), + m_defaultAction( nullptr ) +{ +} + +ToggleActionMenu::ToggleActionMenu( const QString &text, QWidget * parent ) + : KActionMenu( text, parent ), + m_defaultAction( nullptr ) +{ +} + +ToggleActionMenu::ToggleActionMenu( const QIcon &icon, const QString &text, QWidget * parent ) + : KActionMenu( icon, text, parent ), + m_defaultAction( nullptr ) +{ +} + +QWidget * ToggleActionMenu::createWidget( QWidget * parent ) +{ + QToolButton * button = qobject_cast< QToolButton * >( KActionMenu::createWidget( parent ) ); + if ( !button ) { + // This function is used to add a button into the toolbar. + // KActionMenu will plug itself as QToolButton. + // So, if no QToolButton was returned, this was not called the intended way. + return button; + } + + button->setPopupMode( QToolButton::MenuButtonPopup ); + // Remove this menu action from the button, + // so it doesn't compose a menu of this menu action and its own menu. + button->removeAction( this ); + // The button has lost the menu now, let it use the correct menu. + button->setMenu( menu() ); + + if ( m_defaultAction ) { + button->setDefaultAction( m_defaultAction ); + } + + m_buttons.append( QPointer< QToolButton >( button ) ); + + return button; +} + +void ToggleActionMenu::setDefaultAction( QAction *action ) +{ + for ( QPointer< QToolButton > button : qAsConst( m_buttons ) ) + { + if ( button ) + { + button->setDefaultAction( action ); + } + } + + m_defaultAction = action; +} + +QAction * ToggleActionMenu::defaultAction() +{ + return m_defaultAction; +} diff --git a/ui/toolaction.h b/ui/toolaction.h deleted file mode 100644 --- a/ui/toolaction.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2004-2006 by Albert Astals Cid * - * * - * 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 TOOLACTION_H -#define TOOLACTION_H - -#include -#include - -#include - -class QToolButton; - -class ToolAction : public KSelectAction -{ - Q_OBJECT - - public: - explicit ToolAction( QObject *parent = nullptr ); - virtual ~ToolAction(); - - void addAction( QAction *action ); - - protected: - QWidget* createWidget( QWidget *parent ) override; - - private Q_SLOTS: - void slotNewDefaultAction( QAction *action ); - - private: - QList< QPointer< QToolButton > > m_buttons; - QList< QAction * > m_actions; -}; - -#endif diff --git a/ui/toolaction.cpp b/ui/toolaction.cpp deleted file mode 100644 --- a/ui/toolaction.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2004-2006 by Albert Astals Cid * - * * - * 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. * - ***************************************************************************/ - -#include "toolaction.h" - -#include -#include -#include - -#include - -ToolAction::ToolAction( QObject *parent ) - : KSelectAction( parent ) -{ - setText( i18n( "Selection Tools" ) ); -} - -ToolAction::~ToolAction() -{ -} - -void ToolAction::addAction( QAction *action ) -{ - bool setDefault = !m_buttons.isEmpty() ? m_buttons.first()->menu()->actions().isEmpty() : false; - foreach ( QToolButton *button, m_buttons ) - if ( button ) - { - button->menu()->addAction( action ); - if ( setDefault ) - button->setDefaultAction( action ); - } - m_actions.append( action ); -} - -QWidget* ToolAction::createWidget( QWidget *parent ) -{ - QToolBar *toolBar = qobject_cast< QToolBar * >( parent ); - if ( !toolBar ) - return nullptr; - - QToolButton *button = new QToolButton( toolBar ); - button->setAutoRaise( true ); - button->setFocusPolicy( Qt::NoFocus ); - button->setIconSize( toolBar->iconSize() ); - button->setToolButtonStyle( toolBar->toolButtonStyle() ); - button->setPopupMode( QToolButton::MenuButtonPopup ); - button->setMenu( new QMenu( button ) ); - button->setCheckable( true ); - connect(toolBar, &QToolBar::iconSizeChanged, button, &QToolButton::setIconSize); - connect(toolBar, &QToolBar::toolButtonStyleChanged, button, &QToolButton::setToolButtonStyle); - connect(button, &QToolButton::triggered, toolBar, &QToolBar::actionTriggered); - connect( button->menu(), &QMenu::triggered, this, &ToolAction::slotNewDefaultAction ); - - m_buttons.append( button ); - - if ( !m_actions.isEmpty() ) - { - button->setDefaultAction( m_actions.first() ); - foreach ( QAction *action, m_actions ) - { - button->menu()->addAction( action ); - if ( action->isChecked() ) - button->setDefaultAction( action ); - } - button->setToolTip( i18n("Click to use the current selection tool\nClick on the arrow to choose another selection tool") ); - } - - return button; -} - -void ToolAction::slotNewDefaultAction( QAction *action ) -{ - foreach ( QToolButton *button, m_buttons ) - if ( button ) - { - button->setDefaultAction( action ); - button->setToolTip( i18n("Click to use the current selection tool\nClick on the arrow to choose another selection tool") ); - } -} - -#include "moc_toolaction.cpp"